Code

new trunk based on current 1.2
authoroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Wed, 23 May 2007 16:08:14 +0000 (16:08 +0000)
committeroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Wed, 23 May 2007 16:08:14 +0000 (16:08 +0000)
git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk/program@1073 a5681a0c-68f1-0310-ab6d-d61299d08faa

172 files changed:
00README
CONTRIBUTORS
COPYRIGHT
MakeMakefile
Makefile.am
NEWS
NT-BUILD-TIPS.txt [deleted file]
PROJECTS
README
TODO
WIN32-BUILD-TIPS.txt [new file with mode: 0644]
acinclude.m4
bindings/Makefile.am
bindings/perl-piped/RRDp.pm
bindings/perl-piped/t/base.t
bindings/perl-shared/Makefile.PL
bindings/perl-shared/RRDs.pm
bindings/perl-shared/RRDs.ppd
bindings/perl-shared/RRDs.xs
bindings/perl-shared/ntmake.pl
bindings/python/ACKNOWLEDGEMENT [new file with mode: 0644]
bindings/python/AUTHORS [new file with mode: 0644]
bindings/python/COPYING [new file with mode: 0644]
bindings/python/README [new file with mode: 0644]
bindings/python/rrd_extra.h [new file with mode: 0644]
bindings/python/rrdtoolmodule.c [new file with mode: 0644]
bindings/python/setup.py [new file with mode: 0644]
bindings/ruby/CHANGES [new file with mode: 0644]
bindings/ruby/README [new file with mode: 0644]
bindings/ruby/extconf.rb [new file with mode: 0644]
bindings/ruby/main.c [new file with mode: 0644]
bindings/ruby/test.rb [new file with mode: 0755]
bindings/tcl/Makefile.am
bindings/tcl/ifOctets.tcl [deleted file]
bindings/tcl/ifOctets.tcl.in [new file with mode: 0644]
bindings/tcl/tclrrd.c
confignt/config.h [deleted file]
configure.ac
debian/copyright
debian/watch
doc/Makefile.am
doc/bin_dec_hex.pod
doc/cdeftutorial.pod
doc/name.inc
doc/rpntutorial.pod
doc/rrd-beginners.pod
doc/rrdbuild.pod [new file with mode: 0644]
doc/rrdcgi.pod
doc/rrdcreate.pod
doc/rrddump.pod
doc/rrdfetch.pod
doc/rrdfirst.pod
doc/rrdgraph-old.pod
doc/rrdgraph.pod [new file with mode: 0644]
doc/rrdgraph.src [deleted file]
doc/rrdgraph_data.pod [new file with mode: 0644]
doc/rrdgraph_data.src [deleted file]
doc/rrdgraph_examples.pod [new file with mode: 0644]
doc/rrdgraph_examples.src [deleted file]
doc/rrdgraph_graph.pod [new file with mode: 0644]
doc/rrdgraph_graph.src [deleted file]
doc/rrdgraph_rpn.pod [new file with mode: 0644]
doc/rrdgraph_rpn.src [deleted file]
doc/rrdinfo.pod
doc/rrdlast.pod
doc/rrdlastupdate.pod [new file with mode: 0644]
doc/rrdpython.pod [new file with mode: 0644]
doc/rrdresize.pod
doc/rrdrestore.pod
doc/rrdruby.pod [new file with mode: 0644]
doc/rrdthreads.pod
doc/rrdtool-xport.dtd
doc/rrdtool.pod
doc/rrdtune.pod
doc/rrdtutorial.es.pod
doc/rrdtutorial.pod
doc/rrdupdate.pod
doc/rrdxport.pod
doc/see_also.inc [deleted file]
examples/4charts.pl.in
examples/Makefile.am
examples/bigtops.pl.in
examples/minmax.pl.in
examples/perftest.pl.in [new file with mode: 0755]
examples/piped-demo.pl.in
examples/shared-demo.pl.in
examples/stripes.pl.in
favicon.ico [new file with mode: 0644]
libraries/afm/compile_afm.pl
netware/Makefile [new file with mode: 0644]
rrdtool-1.2-release [new file with mode: 0755]
rrdtool.spec
src/DejaVuSansMono-Roman.ttf [new file with mode: 0644]
src/Makefile.am
src/VeraMono.ttf
src/art_rgba_svp.c [new file with mode: 0644]
src/art_rgba_svp.h [new file with mode: 0644]
src/fnv.h
src/gdpng.c
src/get_ver.awk [new file with mode: 0644]
src/getopt.c [deleted file]
src/getopt.h [deleted file]
src/getopt1.c [deleted file]
src/gifsize.c [deleted file]
src/hash_32.c
src/parsetime.c
src/pngsize.c
src/rrd.dsp [deleted file]
src/rrd.h
src/rrd.vcproj [deleted file]
src/rrd_afm.c
src/rrd_afm.h
src/rrd_afm_data.c
src/rrd_afm_data.h
src/rrd_cgi.c
src/rrd_create.c
src/rrd_datalang.c
src/rrd_diff.c
src/rrd_dump.c
src/rrd_error.c
src/rrd_fetch.c
src/rrd_first.c
src/rrd_format.c
src/rrd_format.h
src/rrd_getopt.c [new file with mode: 0644]
src/rrd_getopt.h [new file with mode: 0644]
src/rrd_getopt1.c [new file with mode: 0644]
src/rrd_gfx.c
src/rrd_gfx.h
src/rrd_graph.c
src/rrd_graph.h
src/rrd_graph_helper.c
src/rrd_hw.c
src/rrd_hw.h
src/rrd_info.c
src/rrd_is_thread_safe.h
src/rrd_last.c
src/rrd_lastupdate.c [new file with mode: 0644]
src/rrd_nan_inf.c
src/rrd_not_thread_safe.c
src/rrd_open.c
src/rrd_resize.c
src/rrd_restore.c
src/rrd_rpncalc.c
src/rrd_rpncalc.h
src/rrd_stat.c
src/rrd_thread_safe.c
src/rrd_thread_safe_nt.c
src/rrd_tool.c
src/rrd_tool.h
src/rrd_tune.c
src/rrd_update.c
src/rrd_version.c [new file with mode: 0644]
src/rrd_xport.c
src/rrd_xport.h
src/rrdtool.dsp [deleted file]
src/rrdtool.dsw [deleted file]
src/rrdtool.sln [deleted file]
src/rrdtool.vcproj [deleted file]
src/rrdupdate.c
src/strftime.c [new file with mode: 0644]
src/strftime.h [new file with mode: 0644]
src/unused.h [new file with mode: 0644]
src/win32comp.c [new file with mode: 0644]
win32/Makefile [new file with mode: 0644]
win32/config.h [new file with mode: 0644]
win32/rrd.dsp [new file with mode: 0644]
win32/rrd.vcproj [new file with mode: 0644]
win32/rrd_config.h.msvc [new file with mode: 0644]
win32/rrdtool.dsp [new file with mode: 0644]
win32/rrdtool.dsw [new file with mode: 0644]
win32/rrdtool.vcproj [new file with mode: 0644]

index 7c5753b75235469584883ba9fc3c7e1c5cfe1cd4..5f197b3fc627b1382b5480a395d47dd2de09730e 100644 (file)
--- a/00README
+++ b/00README
@@ -1,6 +1,6 @@
 Title: RRDtool
-Date: 2000-01-10
-Owner: Tobias Oetiker <oetiker@ee.ethz.ch>
+Date: 2005-04-04
+Owner: Tobias Oetiker <tobi@oetiker.ch>
 Group: Software
 
 Round Robin Database Tool
index 77178f67f626748dd9bcdcb370c2106c4ced3063..aaf7718dcec9c881824ba617cbd0b8c727035338 100644 (file)
 I would like to thank to following people for helping to
 bring RRDtool into existence.
 
-Planning and Inspiration
-
-       Daniel Wesemann
-       Krister Karlson
-       Simon Leinen
-
-Debugging and code contributions
-
-       Andreas Kroomaa <andre@ml.ee>
-       Andrew Turner <turner@mint.net> (LAST consolidator)
-       Bernard Fischer <bfischer@syslog.ch> 64bit stuff and --alt-autoscale-max
-       Bill Fenner <fenner@research.att.com>
-       Blair Zajac <bzajac@geostaff.com>
-       Dan Dunn <dandunn@computer.org>
-       Hermann Hueni <hueni@glue.ch> (SunOS porting)
-       Jeff R. Allen <jeff.allen@acm.org> (autoconfigure, portability)  
-       Joel Becker <jlbec@raleigh.ibm.com> AIX
-       Joey Miller <joeym@inficad.com> php3 and php4 bindings
-       Jost.Krieger <Jost.Krieger@ruhr-uni-bochum.de>
-       Larry Leszczynski <larryl@furph.com>
-       Otmar Lendl <O.Lendl@Austria.EU.net> (lots of bugfixes)
-       Paul Joslin <Paul.Joslin@sdrc.com>
-       Philippe.Simonet <Philippe.Simonet@swisscom.com> (NT porting)
-       Poul-Henning Kamp <phk@freebsd.org> CDEF enhancements
-       REIBENSCHUH Alfred <alfred.reibenschuh@it-austria.com> AIX
-        Roman Hoogant <rhoogant@ee.ethz.ch>
-       Russ Wright <rwwright@home.com>
-       Simon Leinen <simon@switch.ch>
-       Stefan Mueller <s.mueller@computer.org> HPUX 11
-       Steve Rader <rader@teak.wiscnet.net> (rrd_cgi debugging and LAST)
-        Terminator rAT <karl_schilke@eli.net>
-        Christophe VG <Christophe.VanGinneken@ubizen.com>
-        Shane O'Donnell <shaneo@opennms.org>
-        Tuc <ttsg@ttsg.com>
-        Mike Mitchell <mcm@unx.sas.com>
-       Ulrich Schilling <schilling@netz.uni-essen.de> AIX
-       Wrolf Courtney <wrolf@wrolf.net> (HP-UX)
-        Alan Lichty <alan_lichty@eli.net>
-        Alex van den Bogaerdt <alex@ergens.op.het.net> (rrd_resize.c and more)
-        Frank Strauss <strauss@escape.de> TCL bindings
-        Jakob Ilves <jilves@se.oracle.com> HPUX 11
-        Jeremy Fischer <jeremy@pobox.com> (Makefile changes & RPM builds)
-        Oleg Cherevko <olwi@icyb.kiev.ua>
-        Rainer Bawidamann <Rainer.Bawidamann@informatik.uni-ulm.de>
-        Selena M Brewington <smbrewin@ichips.intel.com> add_ds
-        Steen Linden <Steen.Linden@ebone.net>
-        Steve Harris <steveh@wesley.com.au> AIX portability
-        Tom Crawley <Tom.Crawley@hi.riotinto.com.au> (GCC&HP configuration)
-       Albert Chin-A-Young <china@thewrittenword.com>
-       Sean McCreary mccreary@xoanon.colorado.edu
-       Bruce Campbell <bruce.campbell@apnic.net>
-       Sean Summers <sean@Fenstermaker.com> (RPM .spec)
-       Christophe Van Ginneken <Christophe.VanGinneken@ubizen.com> (--no-legend)
-       Wolfgang Schrimm <wschrimm@uni-hd.de> xport function
-        Travis Brown <tebrown@csh.rit.edu> 
-       Peter Stamfest <peter@stamfest.at> initial multi-thread support
-       David L. Barker <dave@ncomtech.com> xport function bug fixes
-       Mike Slifcak <slif@bellsouth.net> many rrdtool-1.1.x fixes
-       Peter Speck <speck@vitality.dk> eps/svg/pdf file format code in rrdtool-1.x
-       David Grimes <dgrimes@navisite.com> SQRT/SORT/REV/SHIFT/TREND
-       Henrik Storner <henrik@hswn.dk> make rrd_graph() provide the min/max values of data in graph
-       Radoslaw Karas <rkaras@tyndall.ie>
-
-Documentation
-
-       Alan Lichty <alan_lichty@eli.net>
-       Alex van den Bogaerdt <alex@ergens.op.het.net>
-        Amos Shapira <amos@gezernet.co.il>
-        Kai Siering <kai.siering@mediaways.net>
-        Russ Wright <rwwright@home.com>
-       Steve Rader <rader@teak.wiscnet.net>  
-        Wrolf Courtney <wrolf@wrolf.net>      
-       Tobias Weingartner <weingart@cs.ualberta.ca>
-       hendrik visage <hvisage@is.co.za>
-       Steve Rader <rader@teak.wiscnet.net>
-        Jesús Couto Fandiño
-
-Packaging
-        Henri GOMEZ -- Redhat RPMs
-        Philippe Simonet -- NT Binaries
-
-
-Internet Resources
-        LAN Services AG (www.lan.ch) 
-           for the http://rrdtool.eu.org domain reflector
-
-        Alexander Lucke (lucke@dns-net.de) 
-           and DNS:NET Internet Services (www.dns-net.de)
-              for http://rrdtool.org
-
-Further I would like to note, that RRDtool would not exist without
-the following free software products:
-
-       Perl by Larry Wall
-       libart by Raph Levien
-       freetype by David Turner, Robert Wilhelm, and Werner Lemberg
-       libpng by Glenn Randers-Pehrson / Andreas Eric Dilger / Guy Eric Schalnat
-       cgilib by Martin Schulze
-       zlib by Jean-loup Gailly and Mark Adler
-       SNMP Perl-Module by Simon Leinen
-
-       and last but not least
-       
-       Linux by Linus Torvalds 
-
-I would also like to thank the Department of Electrical Engineering
-at the Swiss Federal Institute of Technology who allow me to
-use their network resources to publish RRDtool ...
-
-During Summer 1999 CAIDA (www.caida.org) has supported me in working full
-time on RRDtool ... A big thank you to them as well.
-
-Tobias Oetiker <oetiker@ee.ethz.ch>
+Alan Lichty <alan_lichty with eli.net> 
+Alan Milligan <alan.milligan@last-bastion.net> Python bindings
+Alex van den Bogaerdt <alex with ergens.op.het.net> (rrd_resize.c and more)
+Amos Shapira <amos with gezernet.co.il>
+Andreas Kroomaa <andre with ml.ee>
+Andrew Turner <turner with mint.net> (LAST consolidator)
+Bernard Fischer <bfischer with syslog.ch> 64bit stuff and --alt-autoscale-max
+Bill Fenner <fenner with research.att.com>
+Blair Zajac <bzajac with geostaff.com>
+Bruce Campbell <bruce.campbell with apnic.net>
+Chin-A-Young <china with thewrittenword.com>
+Christophe VG <Christophe.VanGinneken with ubizen.com>
+Christophe Van Ginneken <Christophe.VanGinneken with ubizen.com> (--no-legend)
+Dan Dunn <dandunn with computer.org>
+Dave Bodenstab <dave@bodenstab.org> AT style time in update, tclfixes
+David Grimes <dgrimes with navisite.com> SQRT/SORT/REV/SHIFT/TREND
+David L. Barker <dave with ncomtech.com> xport function bug fixes
+Frank Strauss <strauss with escape.de> TCL bindings
+Henrik Storner <henrik with hswn.dk> functions for min/max values of data in graph
+Hermann Hueni <hueni with glue.ch> (SunOS porting)
+Jakob Ilves <jilves with se.oracle.com> HPUX 11
+Jeff R. Allen <jeff.allen with acm.org> (autoconfigure, portability)  
+Jeremy Fischer <jeremy with pobox.com> (Makefile changes & RPM builds)
+Jesús Couto Fandiño
+Joel Becker <jlbec with raleigh.ibm.com> AIX
+Joey Miller <joeym with inficad.com>php3 and php4 bindings
+Jost.Krieger <Jost.Krieger with ruhr-uni-bochum.de>
+Kai Siering <kai.siering with mediaways.net>
+Larry Leszczynski <larryl with furph.com>
+McCreary mccreary with xoanon.colorado.edu
+Mike Mitchell <mcm with unx.sas.com>
+Mike Slifcak <slif with bellsouth.net> many rrdtool-1.1.x fixes
+Oleg Cherevko <olwi with icyb.kiev.ua>
+Otmar Lendl <O.Lendl with Austria.EU.net> (lots of bugfixes)
+Paul Joslin <Paul.Joslin with sdrc.com>
+Peter Speck <speck with vitality.dk> eps/svg/pdf file format code in rrdtool-1.x
+Peter Stamfest <peter with stamfest.at> initial multi-thread support
+Peter Breitenlohner <peb with mppmu.mpg.de>  many patches for rrdtool 1.2.x
+Philippe.Simonet <Philippe.Simonet with swisscom.com> (NT porting)
+Poul-Henning Kamp <phk with freebsd.org> CDEF enhancements
+REIBENSCHUH Alfred <alfred.reibenschuh with it-austria.com> AIX
+Radoslaw Karas <rkaras with tyndall.ie>
+Rainer Bawidamann <Rainer.Bawidamann with informatik.uni-ulm.de>
+Roman Hoogant <rhoogant with ee.ethz.ch>
+Ronan Mullally <ronan in 4L.ie>
+Roger J. Meier <roger.meier in terreactive.ch> (arbitrary linelength in rrdtool)
+Russ Wright <rwwright with home.com>
+Sean Summers <sean with Fenstermaker.com> (RPM .spec)
+Selena M Brewington <smbrewin with ichips.intel.com> add_ds
+Shane O'Donnell <shaneo with opennms.org>
+Simon Leinen <simon with switch.ch>
+Steen Linden <Steen.Linden with ebone.net>
+Stefan Mueller <s.mueller with computer.org> HPUX 11
+Steve Harris <steveh with wesley.com.au> AIX portability
+Steve Rader <rader with teak.wiscnet.net> (rrd_cgi debugging and LAST)
+Terminator rAT <karl_schilke with eli.net>
+Tobias Weingartner <weingart with cs.ualberta.ca>
+Tom Crawley <Tom.Crawley with hi.riotinto.com.au> (GCC&HP configuration)
+Travis Brown <tebrown with csh.rit.edu> 
+Tuc <ttsg with ttsg.com>
+Ulf Lilleengen <lulf with pvv.ntnu.no> Python binding for 'rrdtool first'
+Ulrich Schilling <schilling with netz.uni-essen.de> AIX
+Wim Heirman <wim.heirman elis.ugent.be> --units=si option
+Wolfgang Schrimm <wschrimm with uni-hd.de> xport function
+Wrolf Courtney <wrolf with wrolf.net> (HP-UX)
+hendrik visage <hvisage with is.co.za>
+Philippe Simonet <philippe.simonet with swisscom.ch> (Windows Binaries)
+Alexander Lucke (lucke with dns-net.de) 
+ of DNS:NET Internet Services (www.dns-net.de) http://rrdtool.org
+Hedley Simons <heds@metahusky.net>
+Nicola Worthington <nicolaw@cpan.org>
index 89f12894d50412ec451683ec69d1894ba46bd509..ab5c6955bf03d18755486c3ea6cd9188c8f87bc3 100644 (file)
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -2,8 +2,11 @@
  A tool for fast logging of numerical data graphical display
  of this data.
 
- Copyright (c) 1998, 1999 Tobias Oetiker
+ Copyright (c) 1998-2006 Tobias Oetiker
  All rights reserved.
+ GNU GPL License
+ ===============
 
  This program is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the Free
  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+
+ FLOSS License Exception 
+ =======================
+ (Adapted from http://www.mysql.com/company/legal/licensing/foss-exception.html)
+
+ I want specified Free/Libre and Open Source Software ("FLOSS")
+ applications to be able to use specified GPL-licensed RRDtool
+ libraries (the "Program") despite the fact that not all FLOSS licenses are
+ compatible with version 2 of the GNU General Public License (the "GPL").
+ As a special exception to the terms and conditions of version 2.0 of the GPL:
+
+ You are free to distribute a Derivative Work that is formed entirely from
+ the Program and one or more works (each, a "FLOSS Work") licensed under one
+ or more of the licenses listed below, as long as:
+
+   1. You obey the GPL in all respects for the Program and the Derivative
+   Work, except for identifiable sections of the Derivative Work which are
+   not derived from the Program, and which can reasonably be considered
+   independent and separate works in themselves,
+
+   2. all identifiable sections of the Derivative Work which are not derived
+   from the Program, and which can reasonably be considered independent and
+   separate works in themselves,
+
+         1. are distributed subject to one of the FLOSS licenses listed
+         below, and
+
+         2. the object code or executable form of those sections are
+         accompanied by the complete corresponding machine-readable source
+         code for those sections on the same medium and under the same FLOSS
+         license as the corresponding object code or executable forms of
+         those sections, and
+
+   3. any works which are aggregated with the Program or with a Derivative
+   Work on a volume of a storage or distribution medium in accordance with
+   the GPL, can reasonably be considered independent and separate works in
+   themselves which are not derivatives of either the Program, a Derivative
+   Work or a FLOSS Work.
+
+ If the above conditions are not met, then the Program may only be copied,
+ modified, distributed or used under the terms and conditions of the GPL.
+
+ FLOSS License List
+ ==================
+ License name  Version(s)/Copyright Date
+ Academic Free License         2.0
+ Apache Software License       1.0/1.1/2.0
+ Apple Public Source License   2.0
+ Artistic license              From Perl 5.8.0
+ BSD license                   "July 22 1999"
+ Common Public License         1.0
+ GNU Library or "Lesser" General Public License (LGPL) 2.0/2.1
+ IBM Public License, Version    1.0
+ Jabber Open Source License    1.0
+ MIT License (As listed in file MIT-License.txt)       -
+ Mozilla Public License (MPL)  1.0/1.1
+ Open Software License         2.0
+ OpenSSL license (with original SSLeay license)        "2003" ("1998")
+ PHP License                   3.0
+ Python license (CNRI Python License)  -
+ Python Software Foundation License    2.1.1
+ Sleepycat License             "1999"
+ W3C License                   "2001"
+ X11 License                   "2001"
+ Zlib/libpng License           -
+ Zope Public License           2.0
index 26cc0059bf465ca7c01fc3607a56f63cf3a340e6..c936d002201e0fcb923e36afa59aff7f35ecc269 100755 (executable)
@@ -3,6 +3,9 @@
 # Run this script after the first cvs checkout to build
 # makefiles and friends
 
+PATH="/usr/sepp/bin:$PATH"
+export PATH
+
 vcheck (){
   perl <<PERL
 @t = split /\./, "$1";
@@ -29,7 +32,10 @@ then
     ERROR=1
   else
     automake=automake-1.9
-    aclocal="aclocal-1.9  --acdir=/usr/share/aclocal-1.9 -I /usr/share/aclocal/"
+    aclocal="aclocal-1.9"
+    for d in /usr/pack/automake-1.9.5-to/share/aclocal-1.9 /usr/share/aclocal-1.9; do
+      [ -d $d ] && aclocal="$aclocal -I $d"
+    done
   fi
 else
     automake="automake"
@@ -50,17 +56,15 @@ fi
 
 # cleanup
 set -x
-find . -name Makefile | xargs rm -f _UNKNONW_
-find . -name "*.la" | xargs rm -f
+find . -name Makefile | grep -v win32 | grep -v netware | xargs rm -f _UNKNONW_
+find . -name "*.la" | xargs rm -f _UNKNOWN_
 find . -name Makefile.in | xargs rm -f _UNKNONW_
 find . -name .libs | xargs rm -r 
 find . -name .debs | xargs rm -r
 
 $aclocal
 libtoolize --copy --force
-autoheader --warnings=all --force  
+autoheader --force  
 $aclocal
-$automake --foreign --add-missing --force-missing --copy --warnings=all
-autoconf --warnings=all --force
-# one again to make every body happy
-autoreconf
+$automake --foreign --add-missing --force-missing --copy 
+autoconf --force
index 334f941b4ca0c98642eb757f952e775c385d4d7d..4bbab3e13a6b785dc8e7599449a3253046fd26e2 100644 (file)
@@ -2,11 +2,15 @@
 RSYNC = rsync --rsh=ssh
 
 # build the following subdirectories
-SUBDIRS = src bindings doc examples
+SUBDIRS = src doc examples bindings
 
   # the following files are not mentioned in any other Makefile
-EXTRA_DIST = COPYRIGHT CHANGES NT-BUILD-TIPS.txt TODO CONTRIBUTORS THREADS \
-            rrdtool.spec
+EXTRA_DIST = COPYRIGHT CHANGES WIN32-BUILD-TIPS.txt TODO CONTRIBUTORS THREADS \
+            rrdtool.spec favicon.ico win32/config.h win32/rrd.dsp win32/rrd.vcproj \
+            win32/rrdtool.dsp win32/rrdtool.dsw win32/rrdtool.vcproj win32/Makefile \
+            win32/rrd_config.h.msvc netware/Makefile
+
+            
 
 CLEANFILES = config.cache
 
@@ -21,11 +25,6 @@ ACLOCAL_M4= $(top_srcdir)/aclocal.m4
 
 to-docs: to-versync
        (cd doc && $(MAKE) clean && $(MAKE) && $(MAKE) pdf)
-       (cd website && wmk-1.7.4 -f manual tutorial contributors.wml && ./site-sync )
-
-to-versync: 
-       perl -i -p -e '"$(VERSION)" =~ /(\d+)\.(\d+)\.(\d+)/; $$v=sprintf("%1d.%02d0%02d1" ,$${1},$${2},$${3}); s|VERSION\s*=\s*[\d.]+|VERSION = $$v|' perl-*/RRD?.pm
-       perl -i -p -e 's|RRDtool\s+\d+\.\d+\.\d+ |RRDtool $(VERSION) |' src/*.[ch]
 
 to-dist: to-docs dist
        mv $(PACKAGE)-$(VERSION).tar.gz archive
@@ -45,4 +44,7 @@ site-perl-install: all bindings/perl-piped/Makefile bindings/perl-shared/Makefil
 site-tcl-install: all
        cd bindings/tcl && $(MAKE) tcl-install
 
+site-python-install: all
+       cd bindings/python && $(PYTHON) setup.py install
+
 ##END##
diff --git a/NEWS b/NEWS
index f97e4ac9fd2334ca1fa5ab49048180de22b9b07f..156864e7f855a28165ec662c4145ab185ba8a7bd 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,72 +1,62 @@
 RRDTOOL NEWS
 ============
+Major Changes between 1.0.x and 1.2.x
 
-In this file I am noting the major changes to RRDtool
-for details check the cvs ChangeLog
+Graphing
+--------
 
-2004/01/20 Tobi Oetiker <tobi@oetiker.ch>
-  Ripped out all foreign libraries and adapted
-  Configure and Makefiles and accordingly.
+* rewritten graphics generation based on libart.
+  - anti-aliased output
+  - alpha transparency support
+  - truetype fonts
+* additional graphics formats: EPS, PDF, SVG
 
-2002/03/26 Peter Speck <speck@ruc.dk>
-  Contribution of an svg output routine for the new gfx graphing part
+* extended multi-part documentation
 
-2002/03/23 Alex van den Bogaerdt <alex@ergens.op.Het.Net>
-  Several visible changes made to rrd_graph
-  * Pie chart support workable
-  * Elements that are not used do not take up space on the img
-  * Hack for the missing rotated text (see --vertical-label)
-  * Tiny boxes in front of labels now scale with the text
+* VDEF support; define and use variables.  Find, and use, the
+  maximum rate seen by rrdtool; compute and show the average
 
-2002/01/15 Tobias Oetiker <tobi@oetiker.ch>
-  The BIG graph update
-  * Replace libgd with libart
-  * Added freetype
-  * Updated zlib and libpng
-  * rrd_gfx.c intrduced as libart wrapper
-  * LINE takes now a float as argument
-  * RRDtool uses truetype for fonts
-  * thanks to libart there is now full alpha transparenc
-    and antialiasing.
-  * the new option --font lets customize the font
-    and size for various graph elements
-  * Updated to -> libtool 1.4.2 automake 2.12 autoconf 2.52
-  * new --zoom commandline option for zoom ans shrinking
-  ---- Still missing is rotatet text for the yaxis description
-  ---- Still missing is tab support in the text rendere
-  ---- Still missing is autoconf support for a default truetype font
+* Sliding window (trend) analysis
+  Compute a smoother average, for instance over the last 6 CDPs
 
-2001/07/26 Alex van den Bogaerdt <alex@ergens.op.Het.Net>
-  Added TOTAL to the VDEF functions.
+* percentile (95th or other)
+  Remove peaks, 95 percent of all rates are at or below the
+  returned value
 
-2001/07/19 Alex van den Bogaerdt <alex@ergens.op.Het.Net>
-  VDEF support.  This is a variable containing one value
-  and a time component.  This type of variable can hold
-  the result of a function over a complete time series
-  of data (DEF or CDEF) such as the maximum seen, and when.
+Logging
+-------
+* a second logging interface: rrdtool updatev
+  Verbose updating of the database; show CPDs being created
 
-2001/03/10 Jake Brutlag <jakeb@corp.webtv.net>
-  Support for COMPUTE data sources (CDEF data sources). Removes the RPN
-  parser and calculator from rrd_graph and puts then in a new file,
-  rrd_rpncalc.c. Changes to core files rrd_create and rrd_update. Some
-  clean-up of aberrant behavior stuff, including a bug fix. 
-  Documentation update (rrdcreate.pod, rrdupdate.pod). Change xml format.
-  
-2001/03/07 Tobias Oetiker <oetiker@ee.ethz.ch> 
-  Integrated complete rewrite
-  of rrdgraph documentation by Alex van den Bogaerdt
-  <alex@ergens.op.Het.Net>. This also contains info on his planned
-  changes to the rrdgraph module
+* Aberrant Behavior Detection with Holt-Winters Forecasting
+  Compare current data with expected data, detect and log when
+  the rates are outside expected levels
 
-2001/03/02 Tobias Oetiker <oetiker@ee.ethz.ch>
-  Added Aberrant Patch from Jake Brutlag <jakeb@microsoft.com>
-  From now one, new rrd files use version tag 0002. They can
-  NOT be read by the old 1.0.x RRDtools. 
+* COMPUTE data type for artificial data-sources calculating their
+  input using RPN math and data from the other data-sources.
  
-  Jake:
-  Aberrant Behavior Detection support. A brief overview added to
-  rrdtool.pod.  Major updates to rrd_update.c, rrd_create.c. Minor update to
-  other core files.  Updated documentation: rrdcreate.pod, rrdgraph.pod,
-  rrdtune.pod.  This is backwards compatible (i.e. new tool can read and will
-  leave the binary header unchanged for old files).
-  See http://cricket.sourceforge.net/aberrant/rrd_hw.htm
+Incompatibilities
+-----------------
+* Colons in COMMENT arguments to rrdtool graph must be escaped with a backslash
+
+* the --alt-y-mrtg option is gone or rather since 1.2.7 it is back but
+  without functionality.
+
+* In pipe mode, rrdtool answers with OK only if it was successful with the
+  command. Otherwhise the answer will be ERROR...
+
+
+Behind the Scenes
+-----------------
+* In order to support Holt-Winters and Calculated Datasources,
+  the rrdtool data format has changed. While the new version of rrdtool can
+  read files created with rrdtool 1.0.x. It is not possible to read files
+  created by rrdtool-1.2.x with rrdtool-1.0.x
+
+* External libraries are not included with rrdtool anymore. This is in line
+  with todays trend of using shared libraries everywhere. With the exception
+  of the cgi library most things required by rrdtool will be found on every recent
+  system.
+
+* Memory Mapped IO support for faster logging.
diff --git a/NT-BUILD-TIPS.txt b/NT-BUILD-TIPS.txt
deleted file mode 100644 (file)
index 5fa5e7f..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-Compiling RRDtool 1.1.x on Win32 with Microsoft Visual C++:
----------------------------------------------------------------
-7/29/04 Jake Brutlag
-
-As of Jan 2004, code for libraries utilized by rrdtool 
-(png, libart, freetype, and zlib) is no longer distributed with
-rrdtool. This requires some changes to the compile process on
-Win32. The solution described here is to compile rrdtool to
-link against these libraries dynamically. There is an advantage
-to this approach: namely the rrdtool distribution doesn't have to
-worry about how to compile these libraries on Win32. In theory,
-since others already provide and maintain Win32 binaries for these
-libraries the users don't have to worry about how to compile them
-either. The disadvantage of this approach is that the DLLs for
-these libraries must be available on the hosts where rrdtool will run.
-
-Here are step by step instructions for compiling rrdtool.exe and
-the perl shared library (RRDS.dll) with Microsoft Visual C++ 6.0.
-(1) Download libraries rrdtool depends on from GnuWin32:
-http://gnuwin32.sourceforge.net/
-For freetype, libpng, and zlib download the "Complete Package"; each of
-these will be a self-extracting self-installing executable.
-For libart, download both the "Binaries" and "Developer Files" packages.
-Unfortunately at this time GnuWin32 doesn't provide the "Complete Package"
-installer for libart. Perhaps by the time you are following these
-instructions GnuWin32 will have a "Complete Package" for libart.
-(2) Install the GnuWin32 libraries by running the executables for freetype,
-libpng, and zlib. These instructions and the Visual C++ project files
-distributed with rrdtool assume that you will use the default install
-location: C:\Program Files\GnuWin32. Extract the two zip files for libart,
-libart-2.3.3-bin.zip and libart-2.3.3-1-lib.zip into the GnuWin32 directory;
-the appropriate libart files will be added to the include, lib, and bin
-subdirectories.
-(3) Add C:\Program Files\GnuWin32\bin to the PATH (Control Panel ->
-System -> Advanced -> Environment Variables).
-(4) Start Microsoft Visual C++ 6.0. Load the workspace file, rrdtool.dsw,
-from the src subdirectory of your rrdtool code directory.
-(5) Compile the Release build of the rrdtool project (since rrdtool depends
-on the rrd project, the rrd library will also be compiled). At this
-time, the compile will fail in zconf.h, a zlib header file. The problem
-is a preprocessor directive that loads unistd.h. Open zconf.h in VC++
-(this file is in C:\Program Files\GnuWin32\include) and find the following
-code block:
-
-#if 1           /* HAVE_UNISTD_H -- this line is updated by ./configure */
-#  include <sys/types.h> /* for off_t */
-#  include <unistd.h>    /* for SEEK_* and off_t */
-#  ifdef VMS
-#    include <unixio.h>   /* for off_t */
-#  endif
-#  define z_off_t  off_t
-#endif 
-
-Change it to reads as follows (this is code from zlib-1.1.4):
-
-#if HAVE_UNISTD_H
-#  include <sys/types.h> /* for off_t */
-#  include <unistd.h>    /* for SEEK_* and off_t */
-#  ifdef VMS
-#    include <unixio.h>   /* for off_t */
-#  endif
-#  define z_off_t  off_t
-#endif 
-
-Note that it is actually just a one line change. Save the file and
-recompile rrdtool. By the time you are following these instructions
-this issue with zconf.h may be resolved.
-(6) At this point, you can run the executable rrdtool.exe in the
-src\toolrelease subdirectory. Note that if you wish to run rrdtool
-on other machines, you will need the following DLLs installed (on the
-path) on those machines:
-zlib1.dll
-libpng12.dll
-libart_lgpl.dll
-freetype6.dll
-msvcrt.dll
-The names of the first four DLLs might vary from what is listed here
-depending on the versions of the packages you downloaded from GnuWin32.
-The fifth DLL, msvcrt.dll, is a system DLL for most versions of Windows.
-If you are running on old version of Windows, you can install/upgrade to
-IE4.0 to get this DLL.
-(7) To compile the perl-shared library, open a Command Prompt (DOS box)
-and cd to the bindings\perl-shared subdirectory.
-(8) Run vcvars32.bat; this batch file, in your vc98\bin directory will
-set necessary environment options for command line compiling.
-(9) In bindings\perl-shared, run
-perl ntmake.pl
-nmake
-nmake test
-If nmake test succeeds, you are good to go. RRDs.dll is in 
-blib\arch\auto\RRDs. If you plan to install via the Active State ppm
-tool, tar and gzip the blib directory. You can use the RRDs.ppd file
-in bindings\perl-shared directory. Remember that as in the case of
-rrdtool.exe you will need the DLLs listed in (6) on the machine where
-you are going to use RRDs.dll.
-
-Microsoft Visual C++ 7.1 (.NET 2003):
-
-Unfortunately, this is more difficult than with VC++ 6.0. The problem
-is that by default the C runtime dll for VC++ 7.1 is msvcr71.dll rather
-than msvcrt.dll. The GnuWin32 library binaries are all compiled
-to use msvcrt.dll and you can't mix msvcr71.dll and msvcrt.dll in the
-same process. One option is to download the source code for the libraries
-(available from http://gnuwin32.sourceforge.net) recompile them with
-VC++ 7.l. Then all the components will use msvcr71.dll. Once you are
-going to go this route, you can also use static multi-threaded libraries
-and use static linking between rrdtool (or RRDs.dll) and its dependencies.
-
-To use the GnuWin32 library binaries, you need to trick VC++ 7.1 into
-compiling rrdtool to use the older msvcrt.dll. Follow steps (1) - (3)
-as above, then:
-(4) Obtain a different version of the msvcrt.lib import library that
-is compatible with vc7 and points to msvcrt.dll:
-msvcrtlib_for_vc7.zip from http://xchat.org/win32/testing
-Backup msvcrt.lib in your vc7\lib directory 
-(\Program Files\Microsoft Visual Studio .NET 2003\vc7\lib)
-Then extract the msvcrt.lib from the zip file into the vc7\lib directory.
-WARNING: Use this msvcrt.lib at your own risk! This is not a Microsoft
-supplied file nor a file supported by anyone associated with rrdtool.
-(5) Start Microsoft Visual C++ 7.1. Load the solution file, rrdtool.sln,
-from the src subdirectory of your rrdtool code directory. Edit zconf.h,
-as needed, as described under (5) above. Compile the release build of
-the rrdtool project.
-Proceed with steps (6) - (9) as above, if you are using/picking up
-the wrong msvcrt.lib import library then nmake test for perl-shared
-will fail.
-
-Note: it is possible in the future that GnuWin32 will provide Win32
-binaries that utilize msvcr71.dll rather than msvcrt.dll.
-
-5/14/02 Jake Brutlag
-
-These notes share some insight I gained compiling 1.1.x with
-MS Visual C++ 6.0 (using project files). This information may or
-may not be accurate at the time you are reading this.
-
-(1) freetype and rrdtool cannot use precompiled headers (which are
-enabled by default for MSVC++ projects).  MSVC++ 6.0 does not
-support precompiled headers if #include directives contain MACROS.
-(2) Compile Release build with Default optimization, not the
-Maximize Speed optimization. I encountered some strange errors
-(related to argument processing for complex commands like graph--
-perhaps the getopt stuff is too blame) with Maximize Speed.
-(3) libart relies upon config.h (ostensibly generated by the
-configure script-- but of course not on Win32 platforms). ..\..\confignt
-(which contains a static Win32 version of config.h) should be on
-the include path.
-(4) Fonts are located in the %windir%\fonts, so the default font
-is c:\winnt\fonts\cour.ttf. (6/19/02) At Kerry Calvert's suggestion
-this setting was moved to confignt\config.h.
-(5) libart requires a custom build step to generate art_config.h; this
-is done manually via the commands:
-cl -I..\..\confignt gen_art_config.c
-gen_art_config.exe > art_config.h
-
-Currently, to compile rrd.lib and rrdtool.exe using
-the MSVC++ project files, first start MSVC++ 6.0. Open the rrdtool
-workspace (rrdtool.dsw in the src directory). The active project/
-configuration should be rrdtool-Win32 Release. Select Rebuild All
-from the Build menu. The static link library (rrd.lib) will
-be generated in src\release directory and executable will be generated
-in the src\toolrelease directory.
-
-Compiling RRDtool on NT ... work in progress
----------------------------------------------------------------
-                         by Tamas Kovacshazy (khazy@mit.bme.hu)
-
-Persisting Problems with the current NT port:
-
-Unfortunately, the RRD perl modules does not work with Perl
-(ActivePerl) using the current distribution.
-
-The RRD shared perl module can be compiled after some
-modification...
-
-Follow these steps:
-
-0. Install perl if you do not have it!
-   Visit http://www.ActiveState.com/pw32/ for a complete distribution.
-
-1. Copy ..\gd1.2\release\gd.lib  to ..\gd1.2\
-2. Copy ..\src\release\rrd.lib to ..\src
-3. perl Makefile.pl
-
-In this step the system complains about something I do not
-understand. The error message is the following:
-
-Note (probably harmless): No library found for '-lm'
-
-Is a library missing? But it does not stop with an error...
-
-4. nmake test (You must have Visual C++ on the machine!)
-
-After these steps it generates the test files (svgs and rrds),
-and they seem to be good.
-
-The real problem in the shared perl modul is the following:
-
-I do not know how this installation stuff works. The problem is
-that the installation stuff looks for the gd.lib and the
-rrd.lib in the ..\gd1.2 and ..\src directory. The UNIX compile
-puts the files into these directories, but the NT compile does
-not.
-
-It is all for today,
-
-khazy
-
-Tamas Kovacshazy  E-mail: khazy@mit.bme.hu  
-WWW: http://www.mit.bme.hu/~khazy
-Technical University of Budapest 
-Department of Measurement and Information Systems
index dbba94b709aab7fad37630f2dd15c30bd86612ef..68a5fcfb0cf2a151df967cbad8672fd48244b4bd 100644 (file)
--- a/PROJECTS
+++ b/PROJECTS
@@ -3,12 +3,9 @@ NEW RRD DATAFORMAT with Accessor Functions
 
 Interested:
 
-Tobias Oetiker <oetiker@ee.ethz.ch>
+Tobias Oetiker <tobi@oetiker.ch>
 Jake Brutlag <jakeb@microsoft.com>  
 - updating rrd_update to use accessor fks
-Karl Schilke <karl_schilke@eli.net> 
-- changeing data access to mmap
-
 
 Plan:
 
diff --git a/README b/README
index d28600cf7a4dd7f32cf4d79435c70cdfd5153ecf..cba88fd2c8962546cd97f9e43a2c5c6955246fe5 100644 (file)
--- a/README
+++ b/README
@@ -14,75 +14,7 @@ values collected over a definable time period.
 To compile:
 -----------
 
-you need the following libraries installed on your system.
-
-   cgilib-0.5.tar.gz
-   freetype-2.1.5.tar.gz
-   libart_lgpl-2.3.16.tar.gz
-   libpng-1.2.5.tar.gz
-   zlib-1.2.1.tar.gz
-
-you can either get these libraries directly from their original sites
-or you can get copies from 
-
-   http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/pub/libs
-
-the configure program will try to use the libraries with out adding any extra
-flags apart from the ones defined in CPPFLAGS and LDFLAGS. If this does not
-work it will try to get information from pkgconfig.
-
-If your libraries are not installed in standard places and you do not have
-pkgconfig support, then you may want to set CPPFLAGS and LDFLAGS to help
-configure while it tries to find the libraries.
-
-  env CPPFLAGS="-I/scratch/oetiker/cgilib-0.5 \
-                -I/scratch/oetiker/libs/include/libart-2.0 \
-                -I/scratch/oetiker/libs/include \
-                -I/scratch/oetiker/libs/include/freetype2" \
-       LDFLAGS="-L/scratch/oetiker/libs/lib -R/scratch/oetiker/libs/lib \
-                -L/scratch/oetiker/cgilib-0.5" ./configure 
-
-  make             <------ GNU make
-
-  make install     <------ GNU make
-
-This will configure, compile and install RRDtool in
-/usr/local/rrdtool-VERSION. If you prefer to install RRDtool in some other
-place, use
-
-  ./configure --prefix=/some/other/RRDtool-dir
-
-The configure script will try to find your perl installation (5.008
-preferred). If it does not find it, you can still build RRDtool but no perl
-modules will be generated.
-
-By default the perl modules will be installed under the RRDtool install
-directory. This will require you to use a 'use lib' statement in your
-RRDtool perl programs. If you do not care what happens to your site-perl
-directory, you can also use
-
-   --enable-perl-site-install 
-
-when running configure to have the RRD perl modules installed  wherever you
-keep your local perl modules. Doing this reliefs you from using 'use lib' in
-your scripts.
-
-Configure will also look for an TCL installation on your system. If it finds
-one it will build a TCL interface for RRDtool. If you keep tcl in a non
-standard location you can use
-
-  sh configure --with-tcllib=/sw/tcl-8.3/lib
-
-to indicte the right version (note, this must point to the directory where
-tclConfig.sh is located). Note that install will integrate the tcl bindings
-into your tcl installation. It will use a separate directory for each
-version though, so this is not much of a problem. Nevertheless the Tcl
-module will not get intalled by default as Tcl wants its module in the base
-tcl installation where you might not be able to write to. So if you want the
-tcl stuff installed, type
-
-  make site-tcl-install
-
+check out the instructions in doc/rrdbuild.txt
 
 Getting Started:
 ----------------
@@ -107,7 +39,7 @@ How to make Tobi happy:
 -----------------------
 
 If you want to show your appreciation for RRDtool you could make me happy
-by going to ee-staff.ethz.ch/~oetiker/wish and ordering a CD from
+by going to http://tobi.oetiker.ch/wish and ordering a CD from
 my CD wish list ... 
 
 
@@ -121,7 +53,7 @@ rrd-users       For discussion amongst people who use RRDtool in their applicati
 rrd-developers  For people who actually HACK RRDtool code
 
 To subscribe to <MAILGLIST> send a message with the subject 'subscribe'
-to <MAILGLIST>-request@list.ee.ethz.ch.
+to <MAILGLIST>-request@lists.oetiker.ch
 
 Note, that postings to rrd-announce will always be cross-posted 
 to rrd-users and rrd-developers as well.
@@ -137,7 +69,7 @@ Use GNU   diff --unified --recursive olddir newdir   to build your patches.
 
 The latest Version:
 -------------------
-Is available from http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/
+Is available from http://oss.oetiker.ch/rrdtool/
 
 
-Tobias Oetiker <oetiker@ee.ethz.ch>
+Tobias Oetiker <tobi@oetiker.ch>
diff --git a/TODO b/TODO
index 350f2b829c190bc8d75659f0dba02b81a0c574a8..baa64f7fc9d23488597c936b11abb7a32ec23189 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,12 +1,5 @@
 What has to be done before the 1.2.0 Release
 --------------------------------------------
-* Add tab support so that it becomes possible to use proportional
-  fonts in the legend
-
-* Polish up the looks of the generated graphs.
-
-* Remove all unfinished code like the PIE chart stuff.
-
 * Sync Docs with reality (there are things described which have not been
   implemented)
 
@@ -37,7 +30,7 @@ Let the user define the base resolution of the graph independently of
 the pixel resolution. If it is smaller than one pixel it will simply
 be ignored
 
-allow sub second presition for step definition
+allow sub second precision for the step definition
 
 modularise consolidation and acquisition functions
 
@@ -53,8 +46,6 @@ add axis on the right and on top of the graph ...
 
 add configurable counter wrap
 
-95th percentile plotting
-
 build derivatives while plotting
 
 show trend by building moving average and represent it as an arrow
@@ -75,4 +66,3 @@ have configurable role-over limits for counters
 align data points not to GMT but some free offset
 
 allow starting through symlinks called rrdcreate rrdtune and the like
-
diff --git a/WIN32-BUILD-TIPS.txt b/WIN32-BUILD-TIPS.txt
new file mode 100644 (file)
index 0000000..7d731c8
--- /dev/null
@@ -0,0 +1,335 @@
+Compiling RRDtool 1.1.x on Win32 with Microsoft Visual C++:
+---------------------------------------------------------------
+5/1/05 Tobi
+to help windows deal with the reentrant versions of many unix
+calls link with win32comp.c
+
+4/10/05 Tobi
+The windows implementation of strftime does not seem to support
+the ISO 8601 week number (%V) I have therfore included the file
+strftime.[ch] which provides strftime_ ... if you compile rrdtool
+with -Dstrftime=_strftime and link strftime.o then you will
+get propper support for %V.
+
+7/29/04 Jake Brutlag
+
+As of Jan 2004, code for libraries utilized by rrdtool 
+(png, libart, freetype, and zlib) is no longer distributed with
+rrdtool. This requires some changes to the compile process on
+Win32. The solution described here is to compile rrdtool to
+link against these libraries dynamically. There is an advantage
+to this approach: namely the rrdtool distribution doesn't have to
+worry about how to compile these libraries on Win32. In theory,
+since others already provide and maintain Win32 binaries for these
+libraries the users don't have to worry about how to compile them
+either. The disadvantage of this approach is that the DLLs for
+these libraries must be available on the hosts where rrdtool will run.
+
+Here are step by step instructions for compiling rrdtool.exe and
+the perl shared library (RRDS.dll) with Microsoft Visual C++ 6.0.
+(1) Download libraries rrdtool depends on from GnuWin32:
+http://gnuwin32.sourceforge.net/
+For freetype, libpng, and zlib download the "Complete Package"; each of
+these will be a self-extracting self-installing executable.
+For libart, download both the "Binaries" and "Developer Files" packages.
+Unfortunately at this time GnuWin32 doesn't provide the "Complete Package"
+installer for libart. Perhaps by the time you are following these
+instructions GnuWin32 will have a "Complete Package" for libart.
+(2) Install the GnuWin32 libraries by running the executables for freetype,
+libpng, and zlib. These instructions and the Visual C++ project files
+distributed with rrdtool assume that you will use the default install
+location: C:\Program Files\GnuWin32. Extract the two zip files for libart,
+libart-2.3.3-bin.zip and libart-2.3.3-1-lib.zip into the GnuWin32 directory;
+the appropriate libart files will be added to the include, lib, and bin
+subdirectories.
+(3) Add C:\Program Files\GnuWin32\bin to the PATH (Control Panel ->
+System -> Advanced -> Environment Variables).
+(4) Start Microsoft Visual C++ 6.0. Load the workspace file, rrdtool.dsw,
+from the src subdirectory of your rrdtool code directory.
+(5) Compile the Release build of the rrdtool project (since rrdtool depends
+on the rrd project, the rrd library will also be compiled). At this
+time, the compile will fail in zconf.h, a zlib header file. The problem
+is a preprocessor directive that loads unistd.h. Open zconf.h in VC++
+(this file is in C:\Program Files\GnuWin32\include) and find the following
+code block:
+
+#if 1           /* HAVE_UNISTD_H -- this line is updated by ./configure */
+#  include <sys/types.h> /* for off_t */
+#  include <unistd.h>    /* for SEEK_* and off_t */
+#  ifdef VMS
+#    include <unixio.h>   /* for off_t */
+#  endif
+#  define z_off_t  off_t
+#endif 
+
+Change it to reads as follows (this is code from zlib-1.1.4):
+
+#if HAVE_UNISTD_H
+#  include <sys/types.h> /* for off_t */
+#  include <unistd.h>    /* for SEEK_* and off_t */
+#  ifdef VMS
+#    include <unixio.h>   /* for off_t */
+#  endif
+#  define z_off_t  off_t
+#endif 
+
+Note that it is actually just a one line change. Save the file and
+recompile rrdtool. By the time you are following these instructions
+this issue with zconf.h may be resolved.
+(6) At this point, you can run the executable rrdtool.exe in the
+src\toolrelease subdirectory. Note that if you wish to run rrdtool
+on other machines, you will need the following DLLs installed (on the
+path) on those machines:
+zlib1.dll
+libpng12.dll
+libart_lgpl.dll
+freetype6.dll
+msvcrt.dll
+The names of the first four DLLs might vary from what is listed here
+depending on the versions of the packages you downloaded from GnuWin32.
+The fifth DLL, msvcrt.dll, is a system DLL for most versions of Windows.
+If you are running on old version of Windows, you can install/upgrade to
+IE4.0 to get this DLL.
+(7) To compile the perl-shared library, open a Command Prompt (DOS box)
+and cd to the bindings\perl-shared subdirectory.
+(8) Run vcvars32.bat; this batch file, in your vc98\bin directory will
+set necessary environment options for command line compiling.
+(9) In bindings\perl-shared, run
+perl ntmake.pl
+nmake
+nmake test
+If nmake test succeeds, you are good to go. RRDs.dll is in 
+blib\arch\auto\RRDs. If you plan to install via the Active State ppm
+tool, tar and gzip the blib directory. You can use the RRDs.ppd file
+in bindings\perl-shared directory. Remember that as in the case of
+rrdtool.exe you will need the DLLs listed in (6) on the machine where
+you are going to use RRDs.dll.
+
+Microsoft Visual C++ 7.1 (.NET 2003):
+
+Unfortunately, this is more difficult than with VC++ 6.0. The problem
+is that by default the C runtime dll for VC++ 7.1 is msvcr71.dll rather
+than msvcrt.dll. The GnuWin32 library binaries are all compiled
+to use msvcrt.dll and you can't mix msvcr71.dll and msvcrt.dll in the
+same process. One option is to download the source code for the libraries
+(available from http://gnuwin32.sourceforge.net) recompile them with
+VC++ 7.l. Then all the components will use msvcr71.dll. Once you are
+going to go this route, you can also use static multi-threaded libraries
+and use static linking between rrdtool (or RRDs.dll) and its dependencies.
+
+To use the GnuWin32 library binaries, you need to trick VC++ 7.1 into
+compiling rrdtool to use the older msvcrt.dll. Follow steps (1) - (3)
+as above, then:
+(4) Obtain a different version of the msvcrt.lib import library that
+is compatible with vc7 and points to msvcrt.dll:
+msvcrtlib_for_vc7.zip from http://xchat.org/win32/testing
+Backup msvcrt.lib in your vc7\lib directory 
+(\Program Files\Microsoft Visual Studio .NET 2003\vc7\lib)
+Then extract the msvcrt.lib from the zip file into the vc7\lib directory.
+WARNING: Use this msvcrt.lib at your own risk! This is not a Microsoft
+supplied file nor a file supported by anyone associated with rrdtool.
+(5) Start Microsoft Visual C++ 7.1. Load the solution file, rrdtool.sln,
+from the src subdirectory of your rrdtool code directory. Edit zconf.h,
+as needed, as described under (5) above. Compile the release build of
+the rrdtool project.
+Proceed with steps (6) - (9) as above, if you are using/picking up
+the wrong msvcrt.lib import library then nmake test for perl-shared
+will fail.
+
+Note: it is possible in the future that GnuWin32 will provide Win32
+binaries that utilize msvcr71.dll rather than msvcrt.dll.
+
+5/14/02 Jake Brutlag
+
+These notes share some insight I gained compiling 1.1.x with
+MS Visual C++ 6.0 (using project files). This information may or
+may not be accurate at the time you are reading this.
+
+(1) freetype and rrdtool cannot use precompiled headers (which are
+enabled by default for MSVC++ projects).  MSVC++ 6.0 does not
+support precompiled headers if #include directives contain MACROS.
+(2) Compile Release build with Default optimization, not the
+Maximize Speed optimization. I encountered some strange errors
+(related to argument processing for complex commands like graph--
+perhaps the getopt stuff is too blame) with Maximize Speed.
+(3) libart relies upon config.h (ostensibly generated by the
+configure script-- but of course not on Win32 platforms). ..\..\confignt
+(which contains a static Win32 version of config.h) should be on
+the include path.
+(4) Fonts are located in the %windir%\fonts, so the default font
+is c:\winnt\fonts\cour.ttf. (6/19/02) At Kerry Calvert's suggestion
+this setting was moved to confignt\config.h.
+(5) libart requires a custom build step to generate art_config.h; this
+is done manually via the commands:
+cl -I..\..\confignt gen_art_config.c
+gen_art_config.exe > art_config.h
+
+Currently, to compile rrd.lib and rrdtool.exe using
+the MSVC++ project files, first start MSVC++ 6.0. Open the rrdtool
+workspace (rrdtool.dsw in the src directory). The active project/
+configuration should be rrdtool-Win32 Release. Select Rebuild All
+from the Build menu. The static link library (rrd.lib) will
+be generated in src\release directory and executable will be generated
+in the src\toolrelease directory.
+
+Compiling RRDtool on NT ... work in progress
+---------------------------------------------------------------
+                         by Tamas Kovacshazy (khazy@mit.bme.hu)
+
+Persisting Problems with the current NT port:
+
+Unfortunately, the RRD perl modules does not work with Perl
+(ActivePerl) using the current distribution.
+
+The RRD shared perl module can be compiled after some
+modification...
+
+Follow these steps:
+
+0. Install perl if you do not have it!
+   Visit http://www.ActiveState.com/pw32/ for a complete distribution.
+
+1. Copy ..\gd1.2\release\gd.lib  to ..\gd1.2\
+2. Copy ..\src\release\rrd.lib to ..\src
+3. perl Makefile.pl
+
+In this step the system complains about something I do not
+understand. The error message is the following:
+
+Note (probably harmless): No library found for '-lm'
+
+Is a library missing? But it does not stop with an error...
+
+4. nmake test (You must have Visual C++ on the machine!)
+
+After these steps it generates the test files (svgs and rrds),
+and they seem to be good.
+
+The real problem in the shared perl modul is the following:
+
+I do not know how this installation stuff works. The problem is
+that the installation stuff looks for the gd.lib and the
+rrd.lib in the ..\gd1.2 and ..\src directory. The UNIX compile
+puts the files into these directories, but the NT compile does
+not.
+
+It is all for today,
+
+khazy
+
+Tamas Kovacshazy  E-mail: khazy@mit.bme.hu  
+WWW: http://www.mit.bme.hu/~khazy
+Technical University of Budapest 
+Department of Measurement and Information Systems
+
+
+Compiling RRDtool 1.2.x on Win32 with MingW32 gcc:
+---------------------------------------------------------------
+
+1. Obtain and install the current version of the MingW package.
+
+     http://www.mingw.org/download.shtml
+
+   In the MinGW set you will need the gcc and binutils as a minimum.
+
+2. Obtain either of the following awk versions and install in a directory
+   on your System Path:
+
+   - awk.exe
+
+     http://cm.bell-labs.com/cm/cs/awkbook/index.html
+
+     Note: This version has no dependencies to other libs.
+
+   - gawk.exe  (GnuWin32 version)
+
+     http://gnuwin32.sourceforge.net/packages/gawk.htm
+
+     Note: Also fetch the dependant libraries for it from the same page.
+
+3. If you plan to create a 'distribution' release of the RRD Tools, the
+   Makefile.Win32 will copy all the needed files to an output directory and
+   then zip the entire directory. A suitable zip utility can be obtained here:
+
+     http://www.info-zip.org/
+
+   Install in a directory on your System Path.
+
+4. Obtain the following libraries, ideally install them all under a common
+   directory:
+
+   = zlib
+
+     http://oss.oetiker.ch/rrdtool/pub/libs/zlib-1.2.3.tar.gz
+     http://www.zlib.net/
+
+   = libpng
+
+     http://oss.oetiker.ch/rrdtool/pub/libs/libpng-1.2.12.tar.gz
+     http://libpng.sourceforge.net/
+
+   = freetype
+
+     http://oss.oetiker.ch/rrdtool/pub/libs/freetype-2.2.1.tar.gz
+     http://freetype.sourceforge.net/index2.html
+   = libart_lgpl
+
+     http://oss.oetiker.ch/rrdtool/pub/libs/libart_lgpl-2.3.17.tar.gz
+     http://www.levien.com/libart/
+
+     Note: libart_lgpl needs a special tweak because the archive contains
+     only the base directory, but the libart headers are usually included with
+     a directory prefix; therefore create a subfolder 'libart_lgpl' and move
+     all files into this subfolder.
+
+5. Set up for DOS environment.
+
+   Add MingW\bin and MSYS\bin directories to your System path.
+
+   If the libraries share a common directory set the following environment var:
+
+     set LIBBASE=<shared director>
+     e.g set LIBBASE=C:\Libraries
+
+   If the libraries are scattered, set the following environment vers:
+
+     set ZLIBSDK=<path to zlib>
+     e.g set ZLIBSDK=C:\mytest\zlib-1.2.3
+     set LIBPNG=<path to libpng>
+     set LIBFT2=<path to freetype>
+     set LIBART=<path to libart>
+
+   If using the Gnu Awk (gawk.exe), edit the Makefile.Win32 and change the line:
+
+      AWK      = awk
+
+   to
+
+      AWK      = gawk
+
+6. Compile the project.
+
+   All dependent libs are statically linked in. This has the benefit that the
+   binaries do not depend on any other DLLs.
+   In order to build the static freetype lib enter the freetype base directory
+   and type 'make'. If everything is fine a message appears that gcc is detected,
+   and that you should again type 'make'. Follow that in order to build freetype.
+   All other libs are build from the sources with the RRDTool Makefile.Win32.
+
+   Switch to the RRDTOOL .\src directory. Then:
+
+      make -f Makefile.Win32 help
+
+   to see the build options, or
+
+      make -f Makefile.Win32 all
+
+   should build the entire package.
+
+6. Happy Graphing!
+
+
+written by normw & gk.
+
+
index 062216a2b689aed8355d73ff1da4ef4d56d89f9c..b71fe8e8058dd75b7414fcbcf3b37b18739c8ed1 100644 (file)
@@ -9,8 +9,8 @@ dnl if this check fails set the environment variable EX_CHECK_ALL_ERR to YES
 dnl and prints out a helful message
 dnl
 dnl
-dnl EX_CHECK_ALL(library, function, header, pkgconf name, tested-version, homepage)
-dnl              $1       $2        $3      $4            $5              $6
+dnl EX_CHECK_ALL(library, function, header, pkgconf name, tested-version, homepage, cppflags)
+dnl              $1       $2        $3      $4            $5              $6        $7
 dnl
 dnl
 AC_DEFUN([EX_CHECK_ALL],
@@ -19,7 +19,10 @@ AC_DEFUN([EX_CHECK_ALL],
  EX_CHECK_STATE=NO
  ex_check_save_LIBS=${LIBS}
  ex_check_save_CPPFLAGS=${CPPFLAGS}
- ex_check_save_LDFLAGS=${LDPFLAGS}
+ ex_check_save_LDFLAGS=${LDFLAGS}
+ if test "x$7" != "x"; then
+   CPPFLAGS="$CPPFLAGS -I$7"
+ fi
  dnl try compiling naked first
  AC_CHECK_LIB($1,$2, [
     AC_CHECK_HEADER($3,[LIBS="-l$1 ${LIBS}";EX_CHECK_STATE=YES],[])],[])
@@ -34,7 +37,10 @@ AC_DEFUN([EX_CHECK_ALL],
              LIBS=${LIBS}" "`$PKGCONFIG --libs-only-l $4`
             dnl remove the cached value and test again
             unset ac_cv_lib_$1_$2
-             AC_CHECK_LIB($1,$2,[ AC_CHECK_HEADER($3,[EX_CHECK_STATE=YES],[])],[])
+             AC_CHECK_LIB($1,$2,[
+                unset ac_cv_header_`echo $3 | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']`
+                AC_CHECK_HEADER($3,[EX_CHECK_STATE=YES],[])
+            ],[])
           else
              AC_MSG_WARN([
 ----------------------------------------------------------------------------
@@ -59,7 +65,7 @@ AC_DEFUN([EX_CHECK_ALL],
 
   You can find also find an archive copy on
 
-     http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/pub/libs
+     http://oss.oetiker.ch/rrdtool/pub/libs
 
   The last tested version of $4 is $5.
 
@@ -77,6 +83,7 @@ AC_DEFUN([EX_CHECK_ALL],
     AC_LANG_POP(C)
 ]
 )
+
 dnl
 dnl  Ptherad check from http://autoconf-archive.cryp.to/acx_pthread.m4
 dnl
@@ -282,6 +289,12 @@ if test "x$acx_pthread_ok" = xyes; then
         case "${host_cpu}-${host_os}" in
             *-aix* | *-freebsd* | *-darwin*) x_rflag="-D_THREAD_SAFE";;
             *solaris* | *-osf* | *-hpux*) x_rflag="-D_REENTRANT";;
+            *-linux*)
+            if test x"$PTHREAD_CFLAGS" = "x-pthread"; then
+                # For Linux/gcc "-pthread" implies "-lpthread". We need, however, to make this explicit
+                # in PTHREAD_LIBS such that a shared library to be built properly depends on libpthread.
+                PTHREAD_LIBS="-lpthread $PTHREAD_LIBS"
+            fi;;
         esac
         AC_MSG_RESULT(${x_rflag})
         if test "x$x_rflag" != xno; then
@@ -349,6 +362,12 @@ AC_CACHE_VAL([rd_cv_ieee_$2],
 #  define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF)
 #endif
 
+/* solaris 10 it defines isnan such that only forte can compile it ... bad bad  */
+#if (defined(HAVE_ISNAN) && defined(isnan) && defined(HAVE_FPCLASS))
+#  undef isnan
+#  define isnan(a) (fpclass(a) == FP_SNAN || fpclass(a) == FP_QNAN)
+#endif
+
 /* Digital UNIX */
 #if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H))
 #  define HAVE_ISINF 1
@@ -373,21 +392,21 @@ AC_CACHE_VAL([rd_cv_ieee_$2],
 
 #include <stdio.h>
 int main(void){
-    double nan,inf,c,zero;
+    double rrdnan,rrdinf,rrdc,rrdzero;
     $4;
     /* some math to see if we get a floating point exception */
-    zero=sin(0.0); /* don't let the compiler optimize us away */
-    nan=0.0/zero; /* especially here */
-    inf=1.0/zero; /* and here. I want to know if it can do the magic */
+    rrdzero=sin(0.0); /* don't let the compiler optimize us away */
+    rrdnan=0.0/rrdzero; /* especially here */
+    rrdinf=1.0/rrdzero; /* and here. I want to know if it can do the magic */
                  /* at run time without sig fpe */
-    c = inf + nan;
-    c = inf / nan;
-    if (! isnan(nan)) {printf ("not isnan(NaN) ... "); return 1;}
-    if (nan == nan) {printf ("nan == nan ... "); return 1;}
-    if (! isinf(inf)) {printf ("not isinf(oo) ... "); return 1;}
-    if (! isinf(-inf)) {printf ("not isinf(-oo) ... "); return 1;}
-    if (! inf > 0) {printf ("not inf > 0 ... "); return 1;}
-    if (! -inf < 0) {printf ("not -inf < 0 ... "); return 1;}
+    rrdc = rrdinf + rrdnan;
+    rrdc = rrdinf / rrdnan;
+    if (! isnan(rrdnan)) {printf ("not isnan(NaN) ... "); return 1;}
+    if (rrdnan == rrdnan) {printf ("nan == nan ... "); return 1;}
+    if (! isinf(rrdinf)) {printf ("not isinf(oo) ... "); return 1;}
+    if (! isinf(-rrdinf)) {printf ("not isinf(-oo) ... "); return 1;}
+    if (! rrdinf > 0) {printf ("not inf > 0 ... "); return 1;}
+    if (! -rrdinf < 0) {printf ("not -inf < 0 ... "); return 1;}
     return 0;
  }]])],[rd_cv_ieee_$2=yes],[rd_cv_ieee_$2=no],[:])])
 dnl these we run regardles is cached or not
@@ -430,10 +449,100 @@ AC_IEEE([out of the box], works, , , ,
                    PERLFLAGS="CCFLAGS=-DMUST_DISABLE_SIGFPE"],         
                    AC_MSG_ERROR([
 Your Compiler does not do propper IEEE math ... Please find out how to
-make IEEE math work with your compiler and let me know (oetiker@ee.ethz.ch).
+make IEEE math work with your compiler and let me know (tobi@oetiker.ch).
 Check config.log to see what went wrong ...
 ]))])])])])])])])])])
 
 AC_LANG_POP(C)
 
 ])
+
+
+dnl a macro to check for ability to create python extensions
+dnl  AM_CHECK_PYTHON_HEADERS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE])
+dnl function also defines PYTHON_INCLUDES
+AC_DEFUN([AM_CHECK_PYTHON_HEADERS],
+[AC_REQUIRE([AM_PATH_PYTHON])
+AC_MSG_CHECKING(for headers required to compile python extensions)
+dnl deduce PYTHON_INCLUDES
+py_prefix=`$PYTHON -c "import sys; print sys.prefix"`
+py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"`
+PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}"
+if test "$py_prefix" != "$py_exec_prefix"; then
+  PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}"
+fi
+AC_SUBST(PYTHON_INCLUDES)
+dnl check if the headers exist:
+save_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES"
+AC_TRY_CPP([#include <Python.h>],dnl
+[AC_MSG_RESULT(found)
+$1],dnl
+[AC_MSG_RESULT(not found)
+$2])
+CPPFLAGS="$save_CPPFLAGS"
+])
+
+dnl a macro to add some color to the build process.
+dnl CONFIGURE_PART(MESSAGE)
+
+AC_DEFUN([CONFIGURE_PART],[
+case $TERM in
+       #   for the most important terminal types we directly know the sequences
+       xterm|xterm*|vt220|vt220*)
+               T_MD=`awk 'BEGIN { printf("%c%c%c%c", 27, 91, 49, 109); }' </dev/null 2>/dev/null`
+               T_ME=`awk 'BEGIN { printf("%c%c%c", 27, 91, 109); }' </dev/null 2>/dev/null`
+       ;;
+       vt100|vt100*|cygwin)
+               T_MD=`awk 'BEGIN { printf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0); }' </dev/null 2>/dev/null`
+               T_ME=`awk 'BEGIN { printf("%c%c%c%c%c", 27, 91, 109, 0, 0); }' </dev/null 2>/dev/null`
+       ;;
+       *)
+               T_MD=''
+               T_ME=''
+       ;;
+esac
+  AC_MSG_RESULT()
+  AC_MSG_RESULT([${T_MD}$1${T_ME}])
+])
+
+
+dnl ---------------------------------------------------------------------------
+dnl CF_DISABLE_ECHO version: 10 updated: 2003/04/17 22:27:11
+dnl ---------------
+dnl stolen from xterm aclocal.m4
+dnl
+dnl You can always use "make -n" to see the actual options, but it's hard to
+dnl pick out/analyze warning messages when the compile-line is long.
+dnl
+dnl Sets:
+dnl     ECHO_LT - symbol to control if libtool is verbose
+dnl     ECHO_LD - symbol to prefix "cc -o" lines
+dnl     RULE_CC - symbol to put before implicit "cc -c" lines (e.g., .c.o)
+dnl     SHOW_CC - symbol to put before explicit "cc -c" lines
+dnl     ECHO_CC - symbol to put before any "cc" line
+dnl
+AC_DEFUN([CF_DISABLE_ECHO],[
+AC_MSG_CHECKING(if you want to see long compiling messages)
+CF_ARG_DISABLE(echo,
+        [  --disable-echo          display "compiling" commands],
+        [
+    ECHO_LT='--silent'
+    ECHO_LD='@echo linking [$]@;'
+    RULE_CC='   @echo compiling [$]<'
+    SHOW_CC='   @echo compiling [$]@'
+    ECHO_CC='@'
+],[
+    ECHO_LT=''
+    ECHO_LD=''
+    RULE_CC='# compiling'
+    SHOW_CC='# compiling'
+    ECHO_CC=''
+])
+AC_MSG_RESULT($enableval)
+AC_SUBST(ECHO_LT)
+AC_SUBST(ECHO_LD)
+AC_SUBST(RULE_CC)
+AC_SUBST(SHOW_CC)
+AC_SUBST(ECHO_CC)
+])dnl
index 48a7508b768d73bec45416f554a4cd2ccc566806..a0e0907b82d04f8100046474bac9cb718a9ea4f5 100644 (file)
@@ -1,13 +1,36 @@
-SUBDIRS = tcl 
+.PHONY: python ruby
+
+if BUILD_TCL
+SUB_tcl = tcl
+endif
+
+SUBDIRS = $(SUB_tcl)
+
 # the following files are not mentioned in any other Makefile
-EXTRA_DIST = $(shell for A in perl-*; do cat $$A/MANIFEST | sed -e s,^,$$A/, ; done)
+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/rrd_extra.h python/rrdtoolmodule.c python/setup.py
+
 
 # add the following to the all target
-all-local:  @COMP_PERL@
+all-local:  @COMP_PERL@ @COMP_RUBY@ @COMP_PYTHON@
 
 install-data-local:
-       cd perl-piped && test -f Makefile && $(MAKE) install || true
-       cd perl-shared && test -f Makefile && $(MAKE) install || true
+       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
+
+# rules for buildung 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
+python:
+       cd python && env BUILDLIBDIR=../../src/.libs $(PYTHON) setup.py build_ext --rpath=$(libdir) && env LIBDIR=../../src/.libs $(PYTHON) setup.py build
 
 # rules for building the perl module
 perl_piped: perl-piped/Makefile
@@ -17,13 +40,17 @@ perl-piped/Makefile: perl-piped/Makefile.PL
        cd perl-piped && $(PERL) Makefile.PL $(PERL_MAKE_OPTIONS)
 
 perl_shared: perl-shared/Makefile
-       cd perl-shared && $(MAKE) RPATH=$(exec_prefix)/lib
+       cd perl-shared && $(MAKE)
 
 perl-shared/Makefile: perl-shared/Makefile.PL
-       cd perl-shared && $(PERL) Makefile.PL $(PERLFLAGS) $(PERL_MAKE_OPTIONS)
+       cd perl-shared && $(PERL) Makefile.PL $(PERLFLAGS) $(PERL_MAKE_OPTIONS) RPATH=$(libdir)
+# LIBS="$(LDFLAGS) $(LIBS)" $(PERLFLAGS) $(PERL_MAKE_OPTIONS)
 
 clean-local:
-       cd perl-piped && test -f Makefile && $(MAKE) clean || true
-       cd perl-shared && test -f Makefile && $(MAKE) clean || true
-
+       test -f perl-piped/Makefile && cd perl-piped && $(MAKE) clean || true
+       test -f perl-piped/Makefile && rm perl-piped/Makefile || true
+       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 -d python/build && cd python &&  rm -rf build || true
 ##END##
index 89b168ed8f33a696a08b89ae546d7e42ea2ef512..e61a28be77cf659eb23eafaecc794f309d5c087c 100644 (file)
@@ -16,7 +16,7 @@ $answer = B<RRD::read>
 
 $status = B<RRD::end>
 
-B<$RRDp::user>,  B<$RRDp::sys>, B<$RRDp::real>
+B<$RRDp::user>,  B<$RRDp::sys>, B<$RRDp::real>, B<$RRDp::error_mode>, B<$RRDp::error>
 
 =head1 DESCRIPTION
 
@@ -69,6 +69,16 @@ The difference between user + system and real is the time spent
 waiting for things like the hard disk and new input from the perl
 script.
 
+=item B<$RRDp::error_mode> and B<$RRDp::error>
+
+If you set the variable $RRDp::error_mode to the value 'catch' before you run RRDp::read a potential
+ERROR message will not cause the program to abort but will be returned in this variable. If no error
+occurs the variable will be empty.
+
+ $RRDp::error_mode = 'catch';
+ RRDp::cmd qw(info file.rrd);
+ print $RRDp::error if $RRDp::error;
+
 =back
 
 
@@ -89,7 +99,7 @@ For more information on how to use RRDtool, check the manpages.
 
 =head1 AUTHOR
 
-Tobias Oetiker <oetiker@ee.ethz.ch>
+Tobias Oetiker <tobi@oetiker.ch>
 
 =cut
 #'  this is to make cperl.el happy
@@ -110,7 +120,7 @@ sub cmd (@);
 sub end ();
 sub read ();
 
-$VERSION = 1.000331 ;
+$VERSION=1.2023;
 
 sub start ($){
   croak "rrdtool is already running"
@@ -128,6 +138,7 @@ sub start ($){
 sub read () {
   croak "RRDp::read can only be called after RRDp::cmd" 
     unless $Sequence eq 'C';
+  $RRDp::error = undef;
   $Sequence = 'R';
   my $inmask = 0;
   my $srbuf;
@@ -148,9 +159,10 @@ sub read () {
     $minibuf .= $srbuf;
     while ($minibuf =~ s|^(.+?)\n||s) {
       my $line = $1;
-      # print $line,"\n";
-      if ($line =~  m|^ERROR|) {
-       croak $line;
+      # print $line,"\n";      
+      $RRDp::error = undef;
+      if ($line =~  m|^ERROR|) {       
+       $RRDp::error_mode eq 'catch' ? $RRDp::error = $line : croak $line;
        $ERR = 1;
       } 
       elsif ($line =~ m|^OK u:([\d\.]+) s:([\d\.]+) r:([\d\.]+)|){
index b7de1f55c2d70834b11751ec2d7a62d51a1e4148..5f0b2aee08ac41ece8ec20ebd14fefe573add139 100755 (executable)
@@ -23,7 +23,7 @@ $ok_count = 1;
 
 print "ok 1 module load\n";
 
-ok("RRDp::start", RRDp::start "../src/rrdtool" > 0);
+ok("RRDp::start", RRDp::start "../../src/rrdtool" > 0);
 
 $now=time();
 RRDp::cmd qw(create demo.rrd --start ), $now, qw(--step 100 ),
index 598fc99f72e05cc7fb40252f47778afb901da9ec..863444c787c423c14a571c599a2ebe7a5a5a9f3e 100644 (file)
@@ -3,18 +3,35 @@ use Config;
 # See lib/ExtUtils/MakeMaker.pm for details of how to influence
 # the contents of the Makefile that is written.
 
-# Specify the location of the archive containing PIC compiled object files.
-my $R = $^O eq 'Linux' ? "-Wl,--rpath -Wl," : "-R" ;
-my $librrd = "-L../../src/.libs/ $R\$(RPATH) -lrrd";
+# if the last argument when calling Makefile.PL is RPATH=/... and ... is the
+# path to librrd.so then the Makefile will be written such that RRDs.so knows
+# where to find librrd.so later on ... 
+my $R="";
+if ($ARGV[-1] =~ /RPATH=(\S+)/){
+       pop @ARGV;
+       my $rp = $1;
+       for ($^O){
+               /linux/   && do{ $R = "-Wl,--rpath -Wl,$rp"};
+               /hpux/    && do{ $R = "+b$rp"};
+               /solaris/ && do{ $R = "-R$rp"};
+                /aix/     && do{ $R = "-Wl,-blibpath:$rp"};
+       }
+}
+
+# darwin works without this because librrd contains its
+# install_name which will includes the final location of the
+# library after it is installed. This install_name gets transfered
+# to the perl shared object.
+
+my $librrd = "-L../../src/.libs/ $R -lrrd";
 
 WriteMakefile(
     'NAME'         => 'RRDs',
     'VERSION_FROM' => 'RRDs.pm', # finds $VERSION
     'DEFINE'      => "-DPERLPATCHLEVEL=$Config{PATCHLEVEL}",
-    'INC'          => '-I../../src -I../../libraries/gd1.3',
-    # where to look for the necessary libraries 
+    'INC'          => '-I../../src',
     # Perl will figure out which one is valid
-    'depend'      => {'RRDs.c' => "../../src/.libs/librrd.a"},
     'dynamic_lib'  => {'OTHERLDFLAGS' => "$librrd -lm"},
     'realclean'    => {FILES => 't/demo?.rrd t/demo?.png' }
 );
+
index b0d6b7e2c2b3bfd8b23a33ec072dbac36c22934e..95424210594ff7c2e4a9f5778e0e70216fe6fd2d 100644 (file)
@@ -7,7 +7,7 @@ use vars qw(@ISA $VERSION);
 
 require DynaLoader;
 
-$VERSION = 1.100001;
+$VERSION=1.2023;
 
 bootstrap RRDs $VERSION;
 
@@ -26,10 +26,13 @@ RRDs - Access RRDtool as a shared module
   RRDs::info ...
   RRDs::create ...
   RRDs::update ...
+  RRDs::updatev ...
   RRDs::graph ...
   RRDs::fetch ...
   RRDs::tune ...
   RRDs::times(start, end)
+  RRDs::dump ...
+  RRDs::restore ...
 
 =head1 DESCRIPTION
 
@@ -137,6 +140,6 @@ operating in the timezone of your choice.
 
 =head1 AUTHOR
 
-Tobias Oetiker E<lt>oetiker@ee.ethz.chE<gt>
+Tobias Oetiker E<lt>tobi@oetiker.chE<gt>
 
 =cut
index e44f6d3c9b78daba6436921d1d71a40b7deb9c33..3a28cd9e3f8ef777a1d0bd65d5421c4a8a1d1dea 100755 (executable)
@@ -1,7 +1,7 @@
 <SOFTPKG NAME="RRDs" VERSION="1,100001,0,0">
        <TITLE>RRDs</TITLE>
        <ABSTRACT>Round Robin Database Tool</ABSTRACT>
-       <AUTHOR>Tobias Oetiker (oetiker@ee.ethz.ch)</AUTHOR>
+       <AUTHOR>Tobias Oetiker (tobi@oetiker.ch)</AUTHOR>
        <IMPLEMENTATION>
                <OS NAME="MSWin32" />
                <ARCHITECTURE NAME="MSWin32-x86-multi-thread-5.8" />
index 217482ce4bf716ead7bb47ddcc045962509586f7..f84efef67419f876f2c0ff0035eefee0176801cd 100644 (file)
@@ -10,7 +10,25 @@ extern "C" {
 }
 #endif
 
+/*
+ * rrd_tool.h includes config.h, but at least on Ubuntu Breezy Badger
+ * 5.10 with gcc 4.0.2, the C preprocessor picks up Perl's config.h
+ * which is included from the Perl includes and never reads rrdtool's
+ * config.h.  Without including rrdtool's config.h, this module does
+ * not compile, so include it here with an explicit path.
+ *
+ * Because rrdtool's config.h redefines VERSION which is originally
+ * set via Perl's Makefile.PL and passed down to the C compiler's
+ * command line, save the original value and reset it after the
+ * includes.
+ */
+#define VERSION_SAVED VERSION
+#undef VERSION
+#include "../../rrd_config.h"
 #include "../../src/rrd_tool.h"
+#undef VERSION
+#define VERSION VERSION_SAVED
+#undef VERSION_SAVED
 
 /* perl 5.004 compatibility */
 #if PERLPATCHLEVEL < 5 
@@ -29,7 +47,6 @@ extern "C" {
                    argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char)); \
                    strcpy(argv[i+1],handle); \
                } \
-               optind=0; opterr=0; \
                rrd_clear_error();\
                RETVAL=name(items+1,argv); \
                for (i=0; i < items; i++) {\
@@ -53,7 +70,6 @@ extern "C" {
                    argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char)); \
                    strcpy(argv[i+1],handle); \
                } \
-               optind=0; opterr=0; \
                 rrd_clear_error(); \
                 data=name(items+1, argv); \
                 for (i=0; i < items; i++) { \
@@ -203,7 +219,6 @@ rrd_graph(...)
                    argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char));
                    strcpy(argv[i+1],handle);
                }
-               optind=0; opterr=0; 
                rrd_clear_error();
                rrd_graph(items+1,argv,&calcpr,&xsize,&ysize,NULL,&ymin,&ymax); 
                for (i=0; i < items; i++) {
@@ -251,7 +266,6 @@ rrd_fetch(...)
                    argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char));
                    strcpy(argv[i+1],handle);
                }
-               optind=0; opterr=0; 
                rrd_clear_error();
                rrd_fetch(items+1,argv,&start,&end,&step,&ds_cnt,&ds_namv,&data); 
                for (i=0; i < items; i++) {
@@ -330,7 +344,6 @@ rrd_xport(...)
                    argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char));
                    strcpy(argv[i+1],handle);
                }
-               optind=0; opterr=0; 
                rrd_clear_error();
                rrd_xport(items+1,argv,&xsize,&start,&end,&step,&col_cnt,&legend_v,&data); 
                for (i=0; i < items; i++) {
index e3fd3c244415ab8e7ecf76c59c444c10144b5780..047b76f2719ac1b0d48dd4b1d755dcfb77142df5 100644 (file)
@@ -19,7 +19,7 @@ WriteMakefile(
    'LIBS'  => '../../src/release/rrd.lib "/Program Files/GnuWin32/lib/libart_lgpl.lib" "/Program Files/GnuWin32/lib/libz.lib" "/Program Files/GnuWin32/lib/libpng.lib" "/Program Files/GnuWin32/lib/libfreetype.lib"', 
     'realclean'    => {FILES => 't/demo?.rrd t/demo?.png' },
     ($] ge '5.005') ? (
-        'AUTHOR' => 'Tobias Oetiker (oetiker@ee.ethz.ch)',
+        'AUTHOR' => 'Tobias Oetiker (tobi@oetiker.ch)',
         'ABSTRACT' => 'Round Robin Database Tool',
     ) : ()
 
diff --git a/bindings/python/ACKNOWLEDGEMENT b/bindings/python/ACKNOWLEDGEMENT
new file mode 100644 (file)
index 0000000..8cf3658
--- /dev/null
@@ -0,0 +1,7 @@
+ACKNOWLEDGMENT
+==============
+
+This is a list of people who have made contributions to py-rrdtool.
+
+Matthew W. Samsonoff <mws@rochester.rr.com>
+Brian E. Gallew <geek+python@cmu.edu>
diff --git a/bindings/python/AUTHORS b/bindings/python/AUTHORS
new file mode 100644 (file)
index 0000000..b3b5713
--- /dev/null
@@ -0,0 +1 @@
+Hye-Shik Chang <perky@fallin.lv>
diff --git a/bindings/python/COPYING b/bindings/python/COPYING
new file mode 100644 (file)
index 0000000..b1e3f5a
--- /dev/null
@@ -0,0 +1,504 @@
+                 GNU LESSER GENERAL PUBLIC LICENSE
+                      Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                 GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/bindings/python/README b/bindings/python/README
new file mode 100644 (file)
index 0000000..265244f
--- /dev/null
@@ -0,0 +1,28 @@
+Python-RRDtool 0.2.1
+--------------------
+
+The python-rrdtool provides a interface to rrdtool, the wonderful
+graphing and logging utility. This wrapper implementation has
+worked from the scratch (without SWIG), and it's under LGPL.
+
+This module have not documented yet. Please refer pydoc.
+
+
+Project
+-------
+
+Homepage: http://www.nongnu.org/py-rrdtool/
+
+Mailing Lists:
+
+  CVS Checkins     py-rrdtool-cvs@nongnu.org
+  Users & Hackers  py-rrdtool-users@nongnu.org
+
+
+Author
+------
+
+Hye-Shik Chang <perky@FreeBSD.org>
+
+Any comments, suggestions, and/or patches are very welcome.
+Thank you for using py-rrdtool!
diff --git a/bindings/python/rrd_extra.h b/bindings/python/rrd_extra.h
new file mode 100644 (file)
index 0000000..99b5aa0
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *  This file is part of RRDtool.
+ *
+ *  RRDtool is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published
+ *  by the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  RRDtool is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Foobar; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*****************************************************************************
+ * RRDtool 1.0.37  Copyright Tobias Oetiker, 1997 - 2000
+ *****************************************************************************
+ * rrd_tool.h   Common Header File
+ *****************************************************************************
+ * Id: rrd_tool.h,v 1.1.1.1 2002/02/26 10:21:37 oetiker Exp
+ * Log: rrd_tool.h,v
+ * Revision 1.1.1.1  2002/02/26 10:21:37  oetiker
+ * Intial Import
+ *
+ *****************************************************************************/
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#ifndef _RRD_EXTRA_H
+#define _RRD_EXTRA_H
+
+#include "rrd_format.h"
+
+#ifndef WIN32
+#ifndef isnan /* POSIX */
+int isnan(double value);
+#endif
+#else /* Windows only */
+#include <float.h>
+#define isnan _isnan
+#endif
+
+void rrd_free(rrd_t *rrd);
+void rrd_init(rrd_t *rrd);
+
+int rrd_open(char *file_name, FILE **in_file, rrd_t *rrd, int rdwr);
+int readfile(char *file, char **buffer, int skipfirst);
+
+#define RRD_READONLY    0
+#define RRD_READWRITE   1
+
+#endif
+
+#ifdef  __cplusplus
+}
+#endif
diff --git a/bindings/python/rrdtoolmodule.c b/bindings/python/rrdtoolmodule.c
new file mode 100644 (file)
index 0000000..6f5b36c
--- /dev/null
@@ -0,0 +1,542 @@
+/*
+ * rrdtoolmodule.c
+ *
+ * RRDTool Python binding
+ *
+ * Author  : Hye-Shik Chang <perky@fallin.lv>
+ * Date    : $Date: 2003/02/22 07:41:19 $
+ * Created : 23 May 2002
+ *
+ * $Revision: 1.14 $
+ *
+ *  ==========================================================================
+ *  This file is part of py-rrdtool.
+ *
+ *  py-rrdtool is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as published
+ *  by the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  py-rrdtool is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with Foobar; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifdef UNUSED
+#elif defined(__GNUC__)
+# define UNUSED(x) x __attribute__((unused))
+#elif defined(__LCLINT__)
+# define UNUSED(x) /*@unused@*/ x
+#else
+# define UNUSED(x) x
+#endif
+
+static const char *__version__ = "$Revision: 1.14 $";
+
+#include "Python.h"
+#include "rrd.h"
+#include "rrd_extra.h"
+
+static PyObject *ErrorObject;
+extern int optind;
+extern int opterr;
+
+/* forward declaration to keep compiler happy */
+void initrrdtool(void);
+
+static int
+create_args(char *command, PyObject *args, int *argc, char ***argv)
+{
+    PyObject        *o;
+    int              size, i;
+    
+    size    = PyTuple_Size(args);
+    *argv   = PyMem_New(char *, size + 1);
+    if (*argv == NULL)
+        return -1;
+
+    for (i = 0; i < size; i++) {
+        o = PyTuple_GET_ITEM(args, i);
+        if (PyString_Check(o))
+            (*argv)[i + 1] = PyString_AS_STRING(o);
+        else {
+            PyMem_Del(*argv);
+            PyErr_Format(PyExc_TypeError, "argument %d must be string", i);
+            return -1;
+        }
+    }
+    (*argv)[0] = command;
+    *argc = size + 1;
+
+    /* reset getopt state */
+    opterr = optind = 0;
+
+    return 0;
+}
+
+static void
+destroy_args(char ***argv)
+{
+    PyMem_Del(*argv);
+    *argv = NULL;
+}
+
+static char PyRRD_create__doc__[] =
+"create(args..): Set up a new Round Robin Database\n\
+    create filename [--start|-b start time] \
+[--step|-s step] [DS:ds-name:DST:heartbeat:min:max] \
+[RRA:CF:xff:steps:rows]";
+
+static PyObject *
+PyRRD_create(PyObject UNUSED(*self), PyObject *args)
+{
+    PyObject        *r;
+    char           **argv;
+    int              argc;
+
+    if (create_args("create", args, &argc, &argv) < 0)
+        return NULL;
+
+    if (rrd_create(argc, argv) == -1) {
+        PyErr_SetString(ErrorObject, rrd_get_error());
+        rrd_clear_error();
+        r = NULL;
+    } else {
+        Py_INCREF(Py_None);
+        r = Py_None;
+    }
+
+    destroy_args(&argv);
+    return r;
+}
+
+static char PyRRD_update__doc__[] =
+"update(args..): Store a new set of values into the rrd\n"
+"    update filename [--template|-t ds-name[:ds-name]...] "
+"N|timestamp:value[:value...] [timestamp:value[:value...] ...]";
+
+static PyObject *
+PyRRD_update(PyObject UNUSED(*self), PyObject *args)
+{
+    PyObject        *r;
+    char           **argv;
+    int              argc;
+
+    if (create_args("update", args, &argc, &argv) < 0)
+        return NULL;
+
+    if (rrd_update(argc, argv) == -1) {
+        PyErr_SetString(ErrorObject, rrd_get_error());
+        rrd_clear_error();
+        r = NULL;
+    } else {
+        Py_INCREF(Py_None);
+        r = Py_None;
+    }
+
+    destroy_args(&argv);
+    return r;
+}
+
+static char PyRRD_fetch__doc__[] =
+"fetch(args..): fetch data from an rrd.\n"
+"    fetch filename CF [--resolution|-r resolution] "
+"[--start|-s start] [--end|-e end]";
+
+static PyObject *
+PyRRD_fetch(PyObject UNUSED(*self), PyObject *args)
+{
+    PyObject        *r;
+    rrd_value_t     *data, *datai;
+    unsigned long    step, ds_cnt;
+    time_t           start, end;
+    int              argc;
+    char           **argv, **ds_namv;
+
+    if (create_args("fetch", args, &argc, &argv) < 0)
+        return NULL;
+
+    if (rrd_fetch(argc, argv, &start, &end, &step,
+                  &ds_cnt, &ds_namv, &data) == -1) {
+        PyErr_SetString(ErrorObject, rrd_get_error());
+        rrd_clear_error();
+        r = NULL;
+    } else {
+        /* Return :
+          ((start, end, step), (name1, name2, ...), [(data1, data2, ..), ...]) */
+        PyObject    *range_tup, *dsnam_tup, *data_list, *t;
+        unsigned long          i, j, row;
+        rrd_value_t  dv;
+
+        row = ((end - start) / step + 1);
+
+        r = PyTuple_New(3);
+        range_tup = PyTuple_New(3);
+        dsnam_tup = PyTuple_New(ds_cnt);
+        data_list = PyList_New(row);
+        PyTuple_SET_ITEM(r, 0, range_tup);
+        PyTuple_SET_ITEM(r, 1, dsnam_tup);
+        PyTuple_SET_ITEM(r, 2, data_list);
+
+        datai = data;
+
+        PyTuple_SET_ITEM(range_tup, 0, PyInt_FromLong((long)start));
+        PyTuple_SET_ITEM(range_tup, 1, PyInt_FromLong((long)end));
+        PyTuple_SET_ITEM(range_tup, 2, PyInt_FromLong((long)step));
+
+        for (i = 0; i < ds_cnt; i++)
+            PyTuple_SET_ITEM(dsnam_tup, i, PyString_FromString(ds_namv[i]));
+
+        for (i = 0; i < row; i ++) {
+            t = PyTuple_New(ds_cnt);
+            PyList_SET_ITEM(data_list, i, t);
+
+            for (j = 0; j < ds_cnt; j++) {
+                dv = *(datai++);
+                if (isnan(dv)) {
+                    PyTuple_SET_ITEM(t, j, Py_None);
+                    Py_INCREF(Py_None);
+                } else {
+                    PyTuple_SET_ITEM(t, j, PyFloat_FromDouble((double)dv));
+                }
+            }
+        }
+
+        for (i = 0; i < ds_cnt; i++)
+            free(ds_namv[i]);
+        free(ds_namv); /* rrdtool don't use PyMem_Malloc :) */
+        free(data);
+    }
+
+    destroy_args(&argv);
+    return r;
+}
+
+static char PyRRD_graph__doc__[] =
+"graph(args..): Create a graph based on data from one or several RRD\n"
+"    graph filename [-s|--start seconds] "
+"[-e|--end seconds] [-x|--x-grid x-axis grid and label] "
+"[-y|--y-grid y-axis grid and label] [--alt-y-grid] [--alt-y-mrtg] "
+"[--alt-autoscale] [--alt-autoscale-max] [--units-exponent] value "
+"[-v|--vertical-label text] [-w|--width pixels] [-h|--height pixels] "
+"[-i|--interlaced] "
+"[-f|--imginfo formatstring] [-a|--imgformat GIF|PNG|GD] "
+"[-B|--background value] [-O|--overlay value] "
+"[-U|--unit value] [-z|--lazy] [-o|--logarithmic] "
+"[-u|--upper-limit value] [-l|--lower-limit value] "
+"[-g|--no-legend] [-r|--rigid] [--step value] "
+"[-b|--base value] [-c|--color COLORTAG#rrggbb] "
+"[-t|--title title] [DEF:vname=rrd:ds-name:CF] "
+"[CDEF:vname=rpn-expression] [PRINT:vname:CF:format] "
+"[GPRINT:vname:CF:format] [COMMENT:text] "
+"[HRULE:value#rrggbb[:legend]] [VRULE:time#rrggbb[:legend]] "
+"[LINE{1|2|3}:vname[#rrggbb[:legend]]] "
+"[AREA:vname[#rrggbb[:legend]]] "
+"[STACK:vname[#rrggbb[:legend]]]";
+
+static PyObject *
+PyRRD_graph(PyObject UNUSED(*self), PyObject *args)
+{
+    PyObject        *r;
+    char           **argv, **calcpr;
+    int              argc, xsize, ysize, i;
+    double          ymin, ymax;
+    if (create_args("graph", args, &argc, &argv) < 0)
+        return NULL;
+
+    if (rrd_graph(argc, argv, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) == -1) {
+        PyErr_SetString(ErrorObject, rrd_get_error());
+        rrd_clear_error();
+        r = NULL;
+    } else {
+        r = PyTuple_New(3);
+
+        PyTuple_SET_ITEM(r, 0, PyInt_FromLong((long)xsize));
+        PyTuple_SET_ITEM(r, 1, PyInt_FromLong((long)ysize));
+
+        if (calcpr) {
+            PyObject    *e, *t;
+            
+            e = PyList_New(0);
+            PyTuple_SET_ITEM(r, 2, e);
+
+            for(i = 0; calcpr[i]; i++) {
+                t = PyString_FromString(calcpr[i]);
+                PyList_Append(e, t);
+                Py_DECREF(t);
+                free(calcpr[i]);
+            }
+            free(calcpr);
+        } else {
+            Py_INCREF(Py_None);
+            PyTuple_SET_ITEM(r, 2, Py_None);
+        }
+    }
+
+    destroy_args(&argv);
+    return r;
+}
+
+static char PyRRD_tune__doc__[] =
+"tune(args...): Modify some basic properties of a Round Robin Database\n"
+"    tune filename [--heartbeat|-h ds-name:heartbeat] "
+"[--minimum|-i ds-name:min] [--maximum|-a ds-name:max] "
+"[--data-source-type|-d ds-name:DST] [--data-source-rename|-r old-name:new-name]";
+
+static PyObject *
+PyRRD_tune(PyObject UNUSED(*self), PyObject *args)
+{
+    PyObject        *r;
+    char           **argv;
+    int              argc;
+
+    if (create_args("tune", args, &argc, &argv) < 0)
+        return NULL;
+
+    if (rrd_tune(argc, argv) == -1) {
+        PyErr_SetString(ErrorObject, rrd_get_error());
+        rrd_clear_error();
+        r = NULL;
+    } else {
+        Py_INCREF(Py_None);
+        r = Py_None;
+    }
+
+    destroy_args(&argv);
+    return r;
+}
+
+static char PyRRD_first__doc__[] =
+"first(filename): Return the timestamp of the first data sample in an RRD";
+
+static PyObject *
+PyRRD_first(PyObject UNUSED(*self), PyObject *args)
+{
+    PyObject        *r;
+    int              argc, ts;
+    char           **argv;
+
+    if (create_args("first", args, &argc, &argv) < 0)
+        return NULL;
+
+    if ((ts = rrd_first(argc, argv)) == -1) {
+        PyErr_SetString(ErrorObject, rrd_get_error());
+        rrd_clear_error();
+        r = NULL;
+    } else
+        r = PyInt_FromLong((long)ts);
+
+    destroy_args(&argv);
+    return r;
+}
+
+static char PyRRD_last__doc__[] =
+"last(filename): Return the timestamp of the last data sample in an RRD";
+
+static PyObject *
+PyRRD_last(PyObject UNUSED(*self), PyObject *args)
+{
+    PyObject        *r;
+    int              argc, ts;
+    char           **argv;
+
+    if (create_args("last", args, &argc, &argv) < 0)
+        return NULL;
+
+    if ((ts = rrd_last(argc, argv)) == -1) {
+        PyErr_SetString(ErrorObject, rrd_get_error());
+        rrd_clear_error();
+        r = NULL;
+    } else
+        r = PyInt_FromLong((long)ts);
+
+    destroy_args(&argv);
+    return r;
+}
+
+static char PyRRD_resize__doc__[] =
+"resize(args...): alters the size of an RRA.\n"
+"    resize filename rra-num GROW|SHRINK rows";
+
+static PyObject *
+PyRRD_resize(PyObject UNUSED(*self), PyObject *args)
+{
+    PyObject        *r;
+    char           **argv;
+    int              argc, ts;
+
+    if (create_args("resize", args, &argc, &argv) < 0)
+        return NULL;
+
+    if ((ts = rrd_resize(argc, argv)) == -1) {
+        PyErr_SetString(ErrorObject, rrd_get_error());
+        rrd_clear_error();
+        r = NULL;
+    } else {
+        Py_INCREF(Py_None);
+        r = Py_None;
+    }
+
+    destroy_args(&argv);
+    return r;
+}
+
+static char PyRRD_info__doc__[] =
+"info(filename): extract header information from an rrd";
+
+static PyObject *
+PyRRD_info(PyObject UNUSED(*self), PyObject *args)
+{
+    PyObject        *r, *t, *ds;
+    rrd_t            rrd;
+    FILE            *in_file;
+    char            *filename;
+    unsigned long   i, j;
+
+    if (! PyArg_ParseTuple(args, "s:info", &filename))
+        return NULL;
+
+    if (rrd_open(filename, &in_file, &rrd, RRD_READONLY) == -1) {
+        PyErr_SetString(ErrorObject, rrd_get_error());
+        rrd_clear_error();
+        return NULL;
+    }
+    fclose(in_file);
+
+#define DICTSET_STR(dict, name, value) \
+    t = PyString_FromString(value); \
+    PyDict_SetItemString(dict, name, t); \
+    Py_DECREF(t);
+
+#define DICTSET_CNT(dict, name, value) \
+    t = PyInt_FromLong((long)value); \
+    PyDict_SetItemString(dict, name, t); \
+    Py_DECREF(t);
+
+#define DICTSET_VAL(dict, name, value) \
+    t = isnan(value) ? (Py_INCREF(Py_None), Py_None) :  \
+        PyFloat_FromDouble((double)value); \
+    PyDict_SetItemString(dict, name, t); \
+    Py_DECREF(t);
+
+    r = PyDict_New();
+
+    DICTSET_STR(r, "filename", filename);
+    DICTSET_STR(r, "rrd_version", rrd.stat_head->version);
+    DICTSET_CNT(r, "step", rrd.stat_head->pdp_step);
+    DICTSET_CNT(r, "last_update", rrd.live_head->last_up);
+
+    ds = PyDict_New();
+    PyDict_SetItemString(r, "ds", ds);
+    Py_DECREF(ds);
+
+    for (i = 0; i < rrd.stat_head->ds_cnt; i++) {
+        PyObject    *d;
+
+        d = PyDict_New();
+        PyDict_SetItemString(ds, rrd.ds_def[i].ds_nam, d);
+        Py_DECREF(d);
+
+        DICTSET_STR(d, "ds_name", rrd.ds_def[i].ds_nam);
+        DICTSET_STR(d, "type", rrd.ds_def[i].dst);
+        DICTSET_CNT(d, "minimal_heartbeat", rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt);
+        DICTSET_VAL(d, "min", rrd.ds_def[i].par[DS_min_val].u_val);
+        DICTSET_VAL(d, "max", rrd.ds_def[i].par[DS_max_val].u_val);
+        DICTSET_STR(d, "last_ds", rrd.pdp_prep[i].last_ds);
+        DICTSET_VAL(d, "value", rrd.pdp_prep[i].scratch[PDP_val].u_val);
+        DICTSET_CNT(d, "unknown_sec", rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt);
+    }
+
+    ds = PyList_New(rrd.stat_head->rra_cnt);
+    PyDict_SetItemString(r, "rra", ds);
+    Py_DECREF(ds);
+
+    for (i = 0; i < rrd.stat_head->rra_cnt; i++) {
+        PyObject    *d, *cdp;
+
+        d = PyDict_New();
+        PyList_SET_ITEM(ds, i, d);
+
+        DICTSET_STR(d, "cf", rrd.rra_def[i].cf_nam);
+        DICTSET_CNT(d, "rows", rrd.rra_def[i].row_cnt);
+        DICTSET_CNT(d, "pdp_per_row", rrd.rra_def[i].pdp_cnt);
+        DICTSET_VAL(d, "xff", rrd.rra_def[i].par[RRA_cdp_xff_val].u_val);
+
+        cdp = PyList_New(rrd.stat_head->ds_cnt);
+        PyDict_SetItemString(d, "cdp_prep", cdp);
+        Py_DECREF(cdp);
+
+        for (j = 0; j < rrd.stat_head->ds_cnt; j++) {
+            PyObject    *cdd;
+
+            cdd = PyDict_New();
+            PyList_SET_ITEM(cdp, j, cdd);
+
+            DICTSET_VAL(cdd, "value",
+                    rrd.cdp_prep[i*rrd.stat_head->ds_cnt+j].scratch[CDP_val].u_val);
+            DICTSET_CNT(cdd, "unknown_datapoints",
+                    rrd.cdp_prep[i*rrd.stat_head->ds_cnt+j].scratch[CDP_unkn_pdp_cnt].u_cnt);
+        }
+    }
+
+    rrd_free(&rrd);
+
+    return r;
+}
+
+/* List of methods defined in the module */
+#define meth(name, func, doc) {name, (PyCFunction)func, METH_VARARGS, doc}
+
+static PyMethodDef _rrdtool_methods[] = {
+    meth("create",  PyRRD_create,   PyRRD_create__doc__),
+    meth("update",  PyRRD_update,   PyRRD_update__doc__),
+    meth("fetch",   PyRRD_fetch,    PyRRD_fetch__doc__),
+    meth("graph",   PyRRD_graph,    PyRRD_graph__doc__),
+    meth("tune",    PyRRD_tune,     PyRRD_tune__doc__),
+    meth("first",   PyRRD_first,    PyRRD_first__doc__),
+    meth("last",    PyRRD_last,     PyRRD_last__doc__),
+    meth("resize",  PyRRD_resize,   PyRRD_resize__doc__),
+    meth("info",    PyRRD_info,     PyRRD_info__doc__),
+    {NULL, NULL,0,NULL}
+};
+
+#define SET_INTCONSTANT(dict, value) \
+            t = PyInt_FromLong((long)value); \
+            PyDict_SetItemString(dict, #value, t); \
+            Py_DECREF(t);
+#define SET_STRCONSTANT(dict, value) \
+            t = PyString_FromString(value); \
+            PyDict_SetItemString(dict, #value, t); \
+            Py_DECREF(t);
+
+/* Initialization function for the module */
+void
+initrrdtool(void)
+{
+    PyObject    *m, *d, *t;
+
+    /* Create the module and add the functions */
+    m = Py_InitModule("rrdtool", _rrdtool_methods);
+
+    /* Add some symbolic constants to the module */
+    d = PyModule_GetDict(m);
+
+    SET_STRCONSTANT(d, __version__);
+    ErrorObject = PyErr_NewException("rrdtool.error", NULL, NULL);
+    PyDict_SetItemString(d, "error", ErrorObject);
+
+    /* Check for errors */
+    if (PyErr_Occurred())
+        Py_FatalError("can't initialize the rrdtool module");
+}
+
+/*
+ * $Id: _rrdtoolmodule.c,v 1.14 2003/02/22 07:41:19 perky Exp $
+ * ex: ts=8 sts=4 et
+ */
diff --git a/bindings/python/setup.py b/bindings/python/setup.py
new file mode 100644 (file)
index 0000000..7a41a11
--- /dev/null
@@ -0,0 +1,55 @@
+#! /usr/bin/env python
+#
+# setup.py
+#
+# py-rrdtool distutil setup
+#
+# Author  : Hye-Shik Chang <perky@fallin.lv>
+# Date    : $Date: 2003/02/14 02:38:16 $
+# Created : 24 May 2002
+#
+# $Revision: 1.7 $
+#
+#  ==========================================================================
+#  This file is part of py-rrdtool.
+#
+#  py-rrdtool is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU Lesser General Public License as published
+#  by the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  py-rrdtool is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public License
+#  along with Foobar; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+from distutils.core import setup, Extension
+import sys, os
+
+RRDBASE = os.environ.get('LOCALBASE', '../../src')
+library_dir = os.environ.get('BUILDLIBDIR', os.path.join(RRDBASE, 'lib'))
+include_dir = os.environ.get('INCDIR', RRDBASE)
+
+setup(name = "py-rrdtool",
+      version = "0.2.1",
+      description = "Python Interface to RRDTool",
+      author = "Hye-Shik Chang",
+      author_email = "perky@fallin.lv",
+      license = "LGPL",
+      url = "http://oss.oetiker.ch/rrdtool",
+      #packages = ['rrdtool'],
+      ext_modules = [
+          Extension(
+            "rrdtoolmodule",
+            ["rrdtoolmodule.c"],
+            libraries=['rrd'],
+            library_dirs=[library_dir],
+            include_dirs=[include_dir],
+          )
+      ]
+)
diff --git a/bindings/ruby/CHANGES b/bindings/ruby/CHANGES
new file mode 100644 (file)
index 0000000..c84ff29
--- /dev/null
@@ -0,0 +1,3 @@
+2006-07-25 Loïs Lherbier
+ add y_min and y_max parameters to rrd_graph
+ update test.rb to send only strings to RRD.fetch
diff --git a/bindings/ruby/README b/bindings/ruby/README
new file mode 100644 (file)
index 0000000..888a062
--- /dev/null
@@ -0,0 +1,22 @@
+#
+# ruby librrd bindings
+# author: Miles Egan <miles@caddr.com>
+#
+
+- Introduction 
+
+This module provides ruby bindings for librrd, with functionality
+comparable to the native perl bindings.  See test.rb for a script that
+exercises all ruby-librrd functionality.
+
+- Installation
+
+Installation is standard.  Simply run:
+
+ruby extconf.rb
+make
+make install
+
+I hope this works for you.  Please let me know if you have any
+problems or suggestions.  Someday when I'm feeling less lazy I'll
+actually document this thing.  Thanks to Tobi for rrdtool!
diff --git a/bindings/ruby/extconf.rb b/bindings/ruby/extconf.rb
new file mode 100644 (file)
index 0000000..2045e5a
--- /dev/null
@@ -0,0 +1,18 @@
+# $Id: extconf.rb,v 1.2 2001/11/28 18:30:16 miles Exp $
+# Lost ticket pays maximum rate.
+
+require 'mkmf'
+
+if /linux/ =~ RUBY_PLATFORM
+   $LDFLAGS += '-Wl,--rpath -Wl,$(EPREFIX)/lib'
+elsif /solaris/ =~ RUBY_PLATFORM
+   $LDFLAGS += '-R$(EPREFIX)/lib'
+elsif /hpux/ =~ RUBY_PLATFORM
+   $LDFLAGS += '+b$(EPREFIX)/lib'
+elsif /aix/ =~ RUBY_PLATFORM
+   $LDFLAGS += '-Wl,-blibpath:$(EPREFIX)/lib'
+end
+
+dir_config("rrd","../../src","../../src/.libs")
+have_library("rrd", "rrd_create")
+create_makefile("RRD")
diff --git a/bindings/ruby/main.c b/bindings/ruby/main.c
new file mode 100644 (file)
index 0000000..b2eaa68
--- /dev/null
@@ -0,0 +1,259 @@
+/* $Id$
+ * Substantial penalty for early withdrawal.
+ */
+
+#include <unistd.h>
+#include <ruby.h>
+#include <rrd.h>
+
+typedef struct string_arr_t {
+    int len;
+    char **strings;
+} string_arr;
+
+VALUE mRRD;
+VALUE rb_eRRDError;
+
+typedef int (*RRDFUNC)(int argc, char ** argv);
+#define RRD_CHECK_ERROR  \
+    if (rrd_test_error()) \
+      rb_raise(rb_eRRDError, rrd_get_error()); \
+    rrd_clear_error();
+
+string_arr string_arr_new(VALUE rb_strings)
+{
+    string_arr a;
+    char buf[64];
+    int i;
+   
+    Check_Type(rb_strings, T_ARRAY);
+    a.len = RARRAY(rb_strings)->len + 1;
+
+    a.strings = malloc(a.len * sizeof(char *));
+    a.strings[0] = "dummy";     /* first element is a dummy element */
+
+    for (i = 0; i < a.len - 1; i++) {
+        VALUE v = rb_ary_entry(rb_strings, i);
+        switch (TYPE(v)) {
+        case T_STRING:
+            a.strings[i + 1] = strdup(STR2CSTR(v));
+            break;
+        case T_FIXNUM:
+            snprintf(buf, 63, "%d", FIX2INT(v));
+            a.strings[i + 1] = strdup(buf);
+            break;
+        default:
+            rb_raise(rb_eTypeError, "invalid argument");
+            break;
+        }
+    }
+
+    return a;
+}
+
+void string_arr_delete(string_arr a)
+{
+    int i;
+
+    /* skip dummy first entry */
+    for (i = 1; i < a.len; i++) {
+        free(a.strings[i]);
+    }
+
+    free(a.strings);
+}
+
+void reset_rrd_state()
+{
+    optind = 0; 
+    opterr = 0;
+    rrd_clear_error();
+}
+
+VALUE rrd_call(RRDFUNC func, VALUE args)
+{
+    string_arr a;
+
+    a = string_arr_new(args);
+    reset_rrd_state();
+    func(a.len, a.strings);
+    string_arr_delete(a);
+
+    RRD_CHECK_ERROR
+
+    return Qnil;
+}
+
+VALUE rb_rrd_create(VALUE self, VALUE args)
+{
+    return rrd_call(rrd_create, args);
+}
+
+VALUE rb_rrd_dump(VALUE self, VALUE args)
+{
+    return rrd_call(rrd_dump, args);
+}
+
+VALUE rb_rrd_fetch(VALUE self, VALUE args)
+{
+    string_arr a;
+    unsigned long i, j, k, step, ds_cnt;
+    rrd_value_t *raw_data;
+    char **raw_names;
+    VALUE data, names, result;
+    time_t start, end;
+
+    a = string_arr_new(args);
+    reset_rrd_state();
+    rrd_fetch(a.len, a.strings, &start, &end, &step, &ds_cnt, &raw_names, &raw_data);
+    string_arr_delete(a);
+
+    RRD_CHECK_ERROR
+
+    names = rb_ary_new();
+    for (i = 0; i < ds_cnt; i++) {
+        rb_ary_push(names, rb_str_new2(raw_names[i]));
+        free(raw_names[i]);
+    }
+    free(raw_names);
+
+    k = 0;
+    data = rb_ary_new();
+    for (i = start; i <= end; i += step) {
+        VALUE line = rb_ary_new2(ds_cnt);
+        for (j = 0; j < ds_cnt; j++) {
+            rb_ary_store(line, j, rb_float_new(raw_data[k]));
+            k++;
+        }
+        rb_ary_push(data, line);
+    }
+    free(raw_data);
+   
+    result = rb_ary_new2(4);
+    rb_ary_store(result, 0, INT2FIX(start));
+    rb_ary_store(result, 1, INT2FIX(end));
+    rb_ary_store(result, 2, names);
+    rb_ary_store(result, 2, data);
+    return result;
+}
+
+VALUE rb_rrd_graph(VALUE self, VALUE args)
+{
+    string_arr a;
+    char **calcpr, **p;
+    VALUE result, print_results;
+    int xsize, ysize;
+    double ymin, ymax;
+
+    a = string_arr_new(args);
+    reset_rrd_state();
+    rrd_graph(a.len, a.strings, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax);
+    string_arr_delete(a);
+
+    RRD_CHECK_ERROR
+
+    result = rb_ary_new2(3);
+    print_results = rb_ary_new();
+    p = calcpr;
+    for (p = calcpr; p && *p; p++) {
+        rb_ary_push(print_results, rb_str_new2(*p));
+        free(*p);
+    }
+    free(calcpr);
+    rb_ary_store(result, 0, print_results);
+    rb_ary_store(result, 1, INT2FIX(xsize));
+    rb_ary_store(result, 2, INT2FIX(ysize));
+    return result;
+}
+
+/*
+VALUE rb_rrd_info(VALUE self, VALUE args)
+{
+    string_arr a;
+    info_t *p;
+    VALUE result;
+
+    a = string_arr_new(args);
+    data = rrd_info(a.len, a.strings);
+    string_arr_delete(a);
+
+    RRD_CHECK_ERROR
+
+    result = rb_hash_new();
+    while (data) {
+        VALUE key = rb_str_new2(data->key);
+        switch (data->type) {
+        case RD_I_VAL:
+            if (isnan(data->u_val)) {
+                rb_hash_aset(result, key, Qnil);
+            }
+            else {
+                rb_hash_aset(result, key, rb_float_new(data->u_val));
+            }
+            break;
+        case RD_I_CNT:
+            rb_hash_aset(result, key, INT2FIX(data->u_cnt));
+            break;
+        case RD_I_STR:
+            rb_hash_aset(result, key, rb_str_new2(data->u_str));
+            free(data->u_str);
+            break;
+        }
+        p = data;
+        data = data->next;
+        free(p);
+    }
+    return result;
+}
+*/
+
+VALUE rb_rrd_last(VALUE self, VALUE args)
+{
+    string_arr a;
+    time_t last;
+
+    a = string_arr_new(args);
+    reset_rrd_state();
+    last = rrd_last(a.len, a.strings);
+    string_arr_delete(a);
+
+    RRD_CHECK_ERROR
+
+    return rb_funcall(rb_cTime, rb_intern("at"), 1, INT2FIX(last));
+}
+
+VALUE rb_rrd_resize(VALUE self, VALUE args)
+{
+    return rrd_call(rrd_resize, args);
+}
+
+VALUE rb_rrd_restore(VALUE self, VALUE args)
+{
+    return rrd_call(rrd_restore, args);
+}
+
+VALUE rb_rrd_tune(VALUE self, VALUE args)
+{
+    return rrd_call(rrd_tune, args);
+}
+
+VALUE rb_rrd_update(VALUE self, VALUE args)
+{
+    return rrd_call(rrd_update, args);
+}
+
+void Init_RRD() 
+{
+    mRRD = rb_define_module("RRD");
+    rb_eRRDError = rb_define_class("RRDError", rb_eStandardError);
+
+    rb_define_module_function(mRRD, "create", rb_rrd_create, -2);
+    rb_define_module_function(mRRD, "dump", rb_rrd_dump, -2);
+    rb_define_module_function(mRRD, "fetch", rb_rrd_fetch, -2);
+    rb_define_module_function(mRRD, "graph", rb_rrd_graph, -2);
+    rb_define_module_function(mRRD, "last", rb_rrd_last, -2);
+    rb_define_module_function(mRRD, "resize", rb_rrd_resize, -2);
+    rb_define_module_function(mRRD, "restore", rb_rrd_restore, -2);
+    rb_define_module_function(mRRD, "tune", rb_rrd_tune, -2);
+    rb_define_module_function(mRRD, "update", rb_rrd_update, -2);
+}
diff --git a/bindings/ruby/test.rb b/bindings/ruby/test.rb
new file mode 100755 (executable)
index 0000000..4853326
--- /dev/null
@@ -0,0 +1,52 @@
+#!/usr/bin/env ruby
+# $Id: test.rb,v 1.2 2002/10/22 17:34:00 miles Exp $
+# Driver does not carry cash.
+
+$: << '/scratch/rrd12build/lib/ruby/1.8/i386-linux/'
+
+require "RRD"
+
+name = "test"
+rrd = "#{name}.rrd"
+start = Time.now.to_i
+
+puts "creating #{rrd}"
+RRD.create(
+    rrd,
+    "--start", "#{start - 1}",
+    "--step", "300",
+       "DS:a:GAUGE:600:U:U",
+    "DS:b:GAUGE:600:U:U",
+    "RRA:AVERAGE:0.5:1:300")
+puts
+
+puts "updating #{rrd}"
+start.to_i.step(start.to_i + 300 * 300, 300) { |i|
+    RRD.update(rrd, "#{i}:#{rand(100)}:#{Math.sin(i / 800) * 50 + 50}")
+}
+puts
+
+puts "fetching data from #{rrd}"
+(fstart, fend, data) = RRD.fetch(rrd, "--start", start.to_s, "--end", (start + 300 * 300).to_s, "AVERAGE")
+puts "got #{data.length} data points from #{fstart} to #{fend}"
+puts
+
+puts "generating graph #{name}.png"
+RRD.graph(
+   "#{name}.png",
+    "--title", " RubyRRD Demo", 
+    "--start", "#{start+3600}",
+    "--end", "start + 1000 min",
+    "--interlace", 
+    "--imgformat", "PNG",
+    "--width=450",
+    "DEF:a=#{rrd}:a:AVERAGE",
+    "DEF:b=#{rrd}:b:AVERAGE",
+    "CDEF:line=TIME,2400,%,300,LT,a,UNKN,IF",
+    "AREA:b#00b6e4:beta",
+    "AREA:line#0022e9:alpha",
+    "LINE3:line#ff0000")
+puts
+
+print "This script has created #{name}.png in the current directory\n";
+print "This demonstrates the use of the TIME and % RPN operators\n";
index 7fd70129e0ab260a96b740586524196e7c32eacb..c73a6e2e0b1bf87a3d93becf2bcd82c376ce436d 100644 (file)
@@ -1,47 +1,56 @@
 
-EXTRA_DIST = README ifOctets.tcl tclrrd.c
-CLEANFILES = tclrrd.o tclrrd.so
+EXTRA_DIST = README tclrrd.c
 
 VERSION = @VERSION@
 
-CFLAGS = @CFLAGS@
+AM_CFLAGS = @CFLAGS@
+
 TCL_PREFIX = @TCL_PREFIX@
 TCL_SHLIB_LD = @TCL_SHLIB_LD@
 TCL_SHLIB_CFLAGS = @TCL_SHLIB_CFLAGS@
 TCL_SHLIB_SUFFIX = @TCL_SHLIB_SUFFIX@
-TCL_PACKAGE_PATH = $(DESTDIR)@TCL_PACKAGE_PATH@
+TCL_PACKAGE_PATH = @TCL_PACKAGE_PATH@
 TCL_LD_SEARCH_FLAGS = @TCL_LD_SEARCH_FLAGS@
-GD_LIB_DIR       = $(top_srcdir)/@GD_LIB_DIR@
+TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+
+CLEANFILES = tclrrd.o tclrrd.so
 
 SRC_DIR            = $(top_srcdir)/src
-AM_CPPFLAGS        = -I$(TCL_PREFIX)/include -I$(SRC_DIR)  -I$(GD_LIB_DIR)
-LIBDIRS            = -L$(libdir) -L$(SRC_DIR)  -L../src/.libs
+AM_CPPFLAGS        = -I$(TCL_PREFIX)/include -I$(SRC_DIR) -DUSE_TCL_STUBS
+LIBDIRS            = -L$(top_builddir)/src/.libs -L$(top_builddir)/src -L$(libdir)
 LIB_RUNTIME_DIR    = $(libdir)
 
-if COMP_TCL
-
-tclrrd$(TCL_SHLIB_SUFFIX): tclrrd.o
-       $(TCL_SHLIB_LD) $(LIBDIRS) $< -o $@ -lrrd_private -lm
+if BUILD_TCL_SITE
+tclpkgdir = @TCL_PACKAGE_DIR@
+tclpkg_DATA = pkgIndex.tcl
+tclpkg_SCRIPTS = ifOctets.tcl
+else
+pkglib_DATA = pkgIndex.tcl
+pkglib_SCRIPTS = ifOctets.tcl
+endif
 
-tclrrd.o: tclrrd.c
-       $(CC) $(CFLAGS) $(TCL_SHLIB_CFLAGS) $(INCLUDES) -c $< -DVERSION=\"$(VERSION)\"
+# Automake doen't like `tclrrd$(VERSION)$(TCL_SHLIB_SUFFIX)' as
+# library name. So we build and install this library `by hand'.
+#
+# We do, however, specify a lib_LIBRARIES target such that
+# automake creates the directory (if neecessary).
+#
+TCL_RRD_LIB = tclrrd$(VERSION)$(TCL_SHLIB_SUFFIX)
 
-all-local: tclrrd$(TCL_SHLIB_SUFFIX)
+lib_LIBRARIES =
 
-tcl-install: tclrrd$(TCL_SHLIB_SUFFIX)
-       cp tclrrd$(TCL_SHLIB_SUFFIX) $(TCL_PACKAGE_PATH)/tclrrd$(VERSION)$(TCL_SHLIB_SUFFIX)
-       if [ ! -d $(TCL_PACKAGE_PATH)/tclrrd$(VERSION) ] ; then \
-               mkdir $(TCL_PACKAGE_PATH)/tclrrd$(VERSION) ; \
-       fi
-       echo "package ifneeded Rrd $(VERSION) [list load [file join \$$dir .. tclrrd$(VERSION)$(TCL_SHLIB_SUFFIX)]]" > $(TCL_PACKAGE_PATH)/tclrrd$(VERSION)/pkgIndex.tcl
+all-local: $(TCL_RRD_LIB)
 
-else
+$(TCL_RRD_LIB): tclrrd.o
+       $(TCL_SHLIB_LD) $(TCL_LD_SEARCH_FLAGS) $(LIBDIRS) $< -o $@ -lrrd_th -lm $(TCL_STUB_LIB_SPEC) $(LDFLAGS) $(LIBS)
 
-all-local:
+tclrrd.o: tclrrd.c
+       $(CC) $(AM_CFLAGS) $(CFLAGS) $(TCL_SHLIB_CFLAGS) $(AM_CPPFLAGS) -c $< -DVERSION=\"$(VERSION)\"
 
-endif
+pkgIndex.tcl:
+       echo "package ifneeded Rrd $(VERSION) \"load $(libdir)/tclrrd$(VERSION)[info sharedlibextension]\"" > $@
 
-diff:
-       cd .. ; diff -c -u -r -N --exclude Makefile --exclude html --exclude doc --exclude Makefile.in --exclude Makefile.old --exclude perl --exclude aclocal.m4 --exclude configure rrdtool-1.0.13 rrdtool-1.0.13-ibr > rrdtool-1.0.13-ibr.patch
-       
+install-exec-local: $(TCL_RRD_LIB)
+       @$(NORMAL_INSTALL)
+       $(INSTALL_PROGRAM) $(TCL_RRD_LIB) $(DESTDIR)$(libdir)/$(TCL_RRD_LIB)
 
diff --git a/bindings/tcl/ifOctets.tcl b/bindings/tcl/ifOctets.tcl
deleted file mode 100644 (file)
index 34185b2..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/bin/sh
-# the next line restarts using tclsh -*- tcl -*- \
-exec tclsh8.2 "$0" "$@"
-
-#package require Tnm 3.0
-package require Rrd 1.0.13
-
-set rrdfile "[lindex $argv 0]-[lindex $argv 1].rrd"
-
-# create rrdfile if not yet existent
-if {[file exists $rrdfile] == 0} {
-    Rrd::create $rrdfile --step 5 \
-           DS:inOctets:COUNTER:10:U:U DS:outOctets:COUNTER:10:U:U \
-           RRA:AVERAGE:0.5:1:12
-}
-
-# get an snmp session context
-set session [Tnm::snmp generator -address [lindex $argv 0]]
-
-# walk through the ifDescr column to find the right interface
-$session walk descr IF-MIB!ifDescr {
-
-    # is this the right interface?
-    if {"[Tnm::snmp value $descr 0]" == "[lindex $argv 1]"} {
-
-       # get the instance part of this table row
-       set inst [lindex [Tnm::mib split [Tnm::snmp oid $descr 0]] 1]
-
-       # get the two interface's octet counter values
-       set in [lindex [lindex [$session get IF-MIB!ifInOctets.$inst] 0] 2]
-       set out [lindex [lindex [$session get IF-MIB!ifOutOctets.$inst] 0] 2]
-
-       # write the values to the rrd
-       puts "$in $out"
-       Rrd::update $rrdfile --template inOctets:outOctets N:$in:$out
-
-       Rrd::graph gaga.png --title "gaga" \
-               DEF:in=$rrdfile:inOctets:AVERAGE \
-               DEF:out=$rrdfile:outOctets:AVERAGE \
-               AREA:in#0000FF:inOctets \
-               LINE2:out#00C000:outOctets
-
-       #puts [Rrd::fetch $rrdfile AVERAGE]
-    }
-}
diff --git a/bindings/tcl/ifOctets.tcl.in b/bindings/tcl/ifOctets.tcl.in
new file mode 100644 (file)
index 0000000..7a36397
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/sh
+# the next line restarts using tclsh -*- tcl -*- \
+exec tclsh@TCL_VERSION@ "$0" "$@"
+
+#package require Tnm 3.0
+package require Rrd @VERSION@
+
+set rrdfile "[lindex $argv 0]-[lindex $argv 1].rrd"
+
+# create rrdfile if not yet existent
+if {[file exists $rrdfile] == 0} {
+    Rrd::create $rrdfile --step 5 \
+           DS:inOctets:COUNTER:10:U:U DS:outOctets:COUNTER:10:U:U \
+           RRA:AVERAGE:0.5:1:12
+}
+
+# get an snmp session context
+set session [Tnm::snmp generator -address [lindex $argv 0]]
+
+# walk through the ifDescr column to find the right interface
+$session walk descr IF-MIB!ifDescr {
+
+    # is this the right interface?
+    if {"[Tnm::snmp value $descr 0]" == "[lindex $argv 1]"} {
+
+       # get the instance part of this table row
+       set inst [lindex [Tnm::mib split [Tnm::snmp oid $descr 0]] 1]
+
+       # get the two interface's octet counter values
+       set in [lindex [lindex [$session get IF-MIB!ifInOctets.$inst] 0] 2]
+       set out [lindex [lindex [$session get IF-MIB!ifOutOctets.$inst] 0] 2]
+
+       # write the values to the rrd
+       puts "$in $out"
+       Rrd::update $rrdfile --template inOctets:outOctets N:$in:$out
+
+       Rrd::graph gaga.png --title "gaga" \
+               DEF:in=$rrdfile:inOctets:AVERAGE \
+               DEF:out=$rrdfile:outOctets:AVERAGE \
+               AREA:in#0000FF:inOctets \
+               LINE2:out#00C000:outOctets
+
+       #puts [Rrd::fetch $rrdfile AVERAGE]
+    }
+}
index 3cc171151ff22acdf7d7fb14702358e7ad9841a0..11d25dfae86d276fe680725aa4863d83a9d10f15 100644 (file)
@@ -3,6 +3,8 @@
  *
  * Copyright (c) 1999,2000 Frank Strauss, Technical University of Braunschweig.
  *
+ * Thread-safe code copyright (c) 2005 Oleg Derevenetz, CenterTelecom Voronezh ISP.
+ *
  * See the file "COPYING" for information on usage and redistribution
  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  *
 
 
 
+#include <errno.h>
+#include <string.h>
 #include <time.h>
+#include <unistd.h>
 #include <tcl.h>
-#include <rrd_tool.h>
-#include <rrd_format.h>
+#include "../../src/rrd_tool.h"
+#include "../../src/rrd_format.h"
 
+/* support pre-8.4 tcl */
 
+#ifndef CONST84
+#   define CONST84
+#endif
 
-extern int __getopt_initialized;
+extern int Tclrrd_Init(Tcl_Interp *interp);
+extern int Tclrrd_SafeInit(Tcl_Interp *interp);
 
 
 /*
- * some rrd_XXX() functions might modify the argv strings passed to it.
- * Furthermore, they use getopt() without initializing getopt's optind
- * variable themselves. Hence, we need to do some preparation before
+ * some rrd_XXX() and new thread-safe versions of Rrd_XXX()
+ * functions might modify the argv strings passed to it.
+ * Hence, we need to do some preparation before
  * calling the rrd library functions.
  */
-static char ** getopt_init(argc, argv)
-    int argc;
-    char *argv[];
+static char ** getopt_init(int argc, CONST84 char *argv[])
 {
     char **argv2;
     int i;
     
-    optind = 0;
-
     argv2 = calloc(argc, sizeof(char *));
     for (i = 0; i < argc; i++) {
        argv2[i] = strdup(argv[i]);
@@ -43,31 +49,128 @@ static char ** getopt_init(argc, argv)
     return argv2;
 }
 
-static void getopt_cleanup(argc, argv2)
-    int argc;
-    char *argv2[];
+static void getopt_cleanup(int argc, char **argv2)
 {
     int i;
     
     for (i = 0; i < argc; i++) {
-       free(argv2[i]);
+       if (argv2[i] != NULL) {
+           free(argv2[i]);
+       }
     }
     free(argv2);
 }
 
+static void getopt_free_element(argv2, argn)
+    char *argv2[];
+    int  argn;
+{
+    if (argv2[argn] != NULL) {
+       free(argv2[argn]);
+       argv2[argn] = NULL;
+    }
+}
 
+static void getopt_squieeze(argc, argv2)
+    int  *argc;
+    char *argv2[];
+{
+    int i, null_i = 0, argc_tmp = *argc;
 
+    for (i = 0; i < argc_tmp; i++) {
+       if (argv2[i] == NULL) {
+           (*argc)--;
+       } else {
+           argv2[null_i++] = argv2[i];
+       }
+    }
+}
+
+
+
+/* Thread-safe version */
 static int
-Rrd_Create(clientData, interp, argc, argv)
-    ClientData clientData;
-    Tcl_Interp *interp;
-    int argc;
-    char *argv[];
+Rrd_Create(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[])
 {
-    char **argv2;
+    int                                argv_i;
+    char                       **argv2;
+    char                       *parsetime_error = NULL;
+    time_t                     last_up = time(NULL) - 10;
+    long int                   long_tmp;
+    unsigned long int          pdp_step = 300;
+    struct rrd_time_value      last_up_tv;
 
     argv2 = getopt_init(argc, argv);
-    rrd_create(argc, argv2);
+
+    for (argv_i = 1; argv_i < argc; argv_i++) {
+       if (!strcmp(argv2[argv_i], "--start") || !strcmp(argv2[argv_i], "-b")) {
+           if (argv_i++>=argc) {
+               Tcl_AppendResult(interp, "RRD Error: option '",
+                                argv2[argv_i - 1], "' needs an argument", (char *) NULL);
+               getopt_cleanup(argc, argv2);
+               return TCL_ERROR;
+           }
+           if ((parsetime_error = parsetime(argv2[argv_i], &last_up_tv))) {
+               Tcl_AppendResult(interp, "RRD Error: invalid time format: '",
+                                argv2[argv_i], "'", (char *) NULL);
+               getopt_cleanup(argc, argv2);
+               return TCL_ERROR;
+           }
+           if (last_up_tv.type == RELATIVE_TO_END_TIME ||
+               last_up_tv.type == RELATIVE_TO_START_TIME) {
+               Tcl_AppendResult(interp, "RRD Error: specifying time relative to the 'start' ",
+                                "or 'end' makes no sense here", (char *) NULL);
+               getopt_cleanup(argc, argv2);
+               return TCL_ERROR;
+           }
+           last_up = mktime(&last_up_tv.tm) + last_up_tv.offset;
+           if (last_up < 3600*24*365*10) {
+               Tcl_AppendResult(interp, "RRD Error: the first entry to the RRD should be after 1980",
+                                (char *) NULL);
+               getopt_cleanup(argc, argv2);
+               return TCL_ERROR;
+           }
+           getopt_free_element(argv2, argv_i - 1);
+           getopt_free_element(argv2, argv_i);
+       } else if (!strcmp(argv2[argv_i], "--step") || !strcmp(argv2[argv_i], "-s")) {
+           if (argv_i++>=argc) {
+               Tcl_AppendResult(interp, "RRD Error: option '",
+                                argv2[argv_i - 1], "' needs an argument", (char *) NULL);
+               getopt_cleanup(argc, argv2);
+               return TCL_ERROR;
+           }
+           long_tmp = atol(argv2[argv_i]);
+           if (long_tmp < 1) {
+               Tcl_AppendResult(interp, "RRD Error: step size should be no less than one second",
+                                (char *) NULL);
+               getopt_cleanup(argc, argv2);
+               return TCL_ERROR;
+           }
+           pdp_step = long_tmp;
+           getopt_free_element(argv2, argv_i - 1);
+           getopt_free_element(argv2, argv_i);
+       } else if (!strcmp(argv2[argv_i], "--")) {
+           getopt_free_element(argv2, argv_i);
+           break;
+       } else if (argv2[argv_i][0]=='-') {
+           Tcl_AppendResult(interp, "RRD Error: unknown option '",
+                            argv2[argv_i], "'", (char *) NULL);
+           getopt_cleanup(argc, argv2);
+           return TCL_ERROR;
+       }
+    }
+
+    getopt_squieeze(&argc, argv2);
+
+    if (argc < 2) {
+       Tcl_AppendResult(interp, "RRD Error: needs rrd filename",
+                        (char *) NULL);
+       getopt_cleanup(argc, argv2);
+       return TCL_ERROR;
+    }
+
+    rrd_create_r(argv2[1], pdp_step, last_up, argc - 2, argv2 + 2);
+
     getopt_cleanup(argc, argv2);
     
     if (rrd_test_error()) {
@@ -82,18 +185,17 @@ Rrd_Create(clientData, interp, argc, argv)
 
 
 
+/* Thread-safe version */
 static int
-Rrd_Dump(clientData, interp, argc, argv)
-    ClientData clientData;
-    Tcl_Interp *interp;
-    int argc;
-    char *argv[];
+Rrd_Dump(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[])
 {
-    char **argv2;
-    
-    argv2 = getopt_init(argc, argv);
-    rrd_dump(argc, argv2);
-    getopt_cleanup(argv, argv2);
+    if (argc < 2) {
+       Tcl_AppendResult(interp, "RRD Error: needs rrd filename",
+                        (char *) NULL);
+       return TCL_ERROR;
+    }
+
+    rrd_dump_r(argv[1], NULL);
 
     /* NOTE: rrd_dump() writes to stdout. No interaction with TCL. */
 
@@ -109,20 +211,19 @@ Rrd_Dump(clientData, interp, argc, argv)
 
 
 
+/* Thread-safe version */
 static int
-Rrd_Last(clientData, interp, argc, argv)
-    ClientData clientData;
-    Tcl_Interp *interp;
-    int argc;
-    char *argv[];
+Rrd_Last(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[])
 {
     time_t t;
-    char **argv2;
     
-    argv2 = getopt_init(argc, argv);
-    t = rrd_last(argc, argv2);
-    getopt_cleanup(argv, argv2);
+    if (argc < 2) {
+       Tcl_AppendResult(interp, "RRD Error: needs rrd filename",
+                        (char *) NULL);
+       return TCL_ERROR;
+    }
 
+    t = rrd_last_r(argv[1]);
 
     if (rrd_test_error()) {
        Tcl_AppendResult(interp, "RRD Error: ",
@@ -138,18 +239,64 @@ Rrd_Last(clientData, interp, argc, argv)
 
 
 
+/* Thread-safe version */
 static int
-Rrd_Update(clientData, interp, argc, argv)
-    ClientData clientData;
-    Tcl_Interp *interp;
-    int argc;
-    char *argv[];
+Rrd_Update(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[])
 {
-    char **argv2;
+    int                argv_i;
+    char       **argv2, *template = NULL;
     
     argv2 = getopt_init(argc, argv);
-    rrd_update(argc, argv2);
-    getopt_cleanup(argv, argv2);
+
+    for (argv_i = 1; argv_i < argc; argv_i++) {
+       if (!strcmp(argv2[argv_i], "--template") || !strcmp(argv2[argv_i], "-t")) {
+           if (argv_i++>=argc) {
+               Tcl_AppendResult(interp, "RRD Error: option '",
+                                argv2[argv_i - 1], "' needs an argument", (char *) NULL);
+               if (template != NULL) {
+                   free(template);
+               }
+               getopt_cleanup(argc, argv2);
+               return TCL_ERROR;
+           }
+           if (template != NULL) {
+               free(template);
+           }
+           template = strdup(argv2[argv_i]);
+           getopt_free_element(argv2, argv_i - 1);
+           getopt_free_element(argv2, argv_i);
+       } else if (!strcmp(argv2[argv_i], "--")) {
+           getopt_free_element(argv2, argv_i);
+           break;
+       } else if (argv2[argv_i][0]=='-') {
+           Tcl_AppendResult(interp, "RRD Error: unknown option '",
+                            argv2[argv_i], "'", (char *) NULL);
+           if (template != NULL) {
+               free(template);
+           }
+           getopt_cleanup(argc, argv2);
+           return TCL_ERROR;
+       }
+    }
+
+    getopt_squieeze(&argc, argv2);
+
+    if (argc < 2) {
+       Tcl_AppendResult(interp, "RRD Error: needs rrd filename",
+                        (char *) NULL);
+       if (template != NULL) {
+           free(template);
+       }
+       getopt_cleanup(argc, argv2);
+       return TCL_ERROR;
+    }
+
+    rrd_update_r(argv2[1], template, argc - 2, argv2 + 2);
+
+    if (template != NULL) {
+       free(template);
+    }
+    getopt_cleanup(argc, argv2);
 
     if (rrd_test_error()) {
        Tcl_AppendResult(interp, "RRD Error: ",
@@ -161,16 +308,49 @@ Rrd_Update(clientData, interp, argc, argv)
     return TCL_OK;
 }
 
-
+static int
+Rrd_Lastupdate(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[])
+{
+   time_t last_update;
+   char **argv2;
+   char **ds_namv;
+   char **last_ds;
+   char s[30];
+   Tcl_Obj *listPtr;
+   unsigned long ds_cnt, i;
+
+   argv2 = getopt_init(argc, argv);
+   if (rrd_lastupdate(argc-1, argv2, &last_update,
+       &ds_cnt, &ds_namv, &last_ds) == 0) {
+          listPtr = Tcl_GetObjResult(interp);
+           for (i=0; i<ds_cnt; i++) {
+              sprintf(s, " %28s", ds_namv[i]);
+              Tcl_ListObjAppendElement(interp, listPtr,
+                      Tcl_NewStringObj(s, -1));
+           sprintf(s, "\n\n%10lu:", last_update);
+              Tcl_ListObjAppendElement(interp, listPtr,
+                      Tcl_NewStringObj(s, -1));
+           for (i=0; i<ds_cnt; i++) {
+               sprintf(s, " %s", last_ds[i]);
+              Tcl_ListObjAppendElement(interp, listPtr,
+                      Tcl_NewStringObj(s, -1));
+               free(last_ds[i]);
+               free(ds_namv[i]);
+           }
+           sprintf(s, "\n");
+          Tcl_ListObjAppendElement(interp, listPtr,
+                   Tcl_NewStringObj(s, -1));
+           free(last_ds);
+           free(ds_namv);
+          }
+    }
+    return TCL_OK;
+}
 
 static int
-Rrd_Fetch(clientData, interp, argc, argv)
-    ClientData clientData;
-    Tcl_Interp *interp;
-    int argc;
-    char *argv[];
+Rrd_Fetch(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[])
 {
-    time_t start, end;
+    time_t start, end, j;
     unsigned long step, ds_cnt, i, ii;
     rrd_value_t *data, *datai;
     char **ds_namv;
@@ -183,7 +363,7 @@ Rrd_Fetch(clientData, interp, argc, argv)
                  &ds_cnt, &ds_namv, &data) != -1) {
         datai = data;
         listPtr = Tcl_GetObjResult(interp);
-        for (i = start; i <= end; i += step) {
+        for (j = start; j <= end; j += step) {
             for (ii = 0; ii < ds_cnt; ii++) {
                sprintf(s, "%.2f", *(datai++));
                 Tcl_ListObjAppendElement(interp, listPtr,
@@ -194,7 +374,7 @@ Rrd_Fetch(clientData, interp, argc, argv)
         free(ds_namv);
         free(data);
     }
-    getopt_cleanup(argv, argv2);
+    getopt_cleanup(argc, argv2);
 
     if (rrd_test_error()) {
        Tcl_AppendResult(interp, "RRD Error: ",
@@ -209,25 +389,83 @@ Rrd_Fetch(clientData, interp, argc, argv)
 
 
 static int
-Rrd_Graph(clientData, interp, argc, argv)
-    ClientData clientData;
-    Tcl_Interp *interp;
-    int argc;
-    char *argv[];
+Rrd_Graph(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[])
 {
-    char **calcpr;
-    int xsize, ysize;
+    Tcl_Channel channel;
+    int mode, fd2;
+    ClientData fd1;
+    FILE *stream = NULL;
+    char **calcpr = NULL;
+    int rc, xsize, ysize;
     double ymin, ymax;
-    Tcl_Obj *listPtr;
+    char dimensions[50];
     char **argv2;
+    CONST84 char *save;
     
-    calcpr = NULL;
+    /*
+     * If the "filename" is a Tcl fileID, then arrange for rrd_graph() to write to
+     * that file descriptor.  Will this work with windoze?  I have no idea.
+     */
+    if ((channel = Tcl_GetChannel(interp, argv[1], &mode)) != NULL) {
+       /*
+        * It >is< a Tcl fileID
+        */
+       if (!(mode & TCL_WRITABLE)) {
+           Tcl_AppendResult(interp, "channel \"", argv[1],
+               "\" wasn't opened for writing", (char *) NULL);
+           return TCL_ERROR;
+       }
+       /*
+        * Must flush channel to make sure any buffered data is written before
+        * rrd_graph() writes to the stream
+        */
+       if (Tcl_Flush(channel) != TCL_OK) {
+           Tcl_AppendResult(interp, "flush failed for \"", argv[1], "\": ",
+               strerror(Tcl_GetErrno()), (char *) NULL);
+           return TCL_ERROR;
+       }
+       if (Tcl_GetChannelHandle(channel, TCL_WRITABLE, &fd1) != TCL_OK) {
+           Tcl_AppendResult(interp, "cannot get file descriptor associated with \"",
+               argv[1], "\"", (char *) NULL);
+           return TCL_ERROR;
+       }
+       /*
+        * Must dup() file descriptor so we can fclose(stream), otherwise the fclose()
+        * would close Tcl's file descriptor
+        */
+       if ((fd2 = dup((int)fd1)) == -1) {
+           Tcl_AppendResult(interp, "dup() failed for file descriptor associated with \"",
+               argv[1], "\": ", strerror(errno), (char *) NULL);
+           return TCL_ERROR;
+       }
+       /*
+        * rrd_graph() wants a FILE*
+        */
+       if ((stream = fdopen(fd2, "wb")) == NULL) {
+           Tcl_AppendResult(interp, "fdopen() failed for file descriptor associated with \"",
+               argv[1], "\": ", strerror(errno), (char *) NULL);
+           close(fd2);         /* plug potential file descriptor leak */
+           return TCL_ERROR;
+       }
 
-    argv2 = getopt_init(argc, argv);
-    if (rrd_graph(argc, argv2, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) != -1 ) {
-        listPtr = Tcl_GetObjResult(interp);
-        Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(xsize));
-        Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(ysize));
+       save = argv[1];
+       argv[1] = "-";
+       argv2 = getopt_init(argc, argv);
+       argv[1] = save;
+    } else {
+       Tcl_ResetResult(interp);        /* clear error from Tcl_GetChannel() */
+       argv2 = getopt_init(argc, argv);
+    }
+
+    rc = rrd_graph(argc, argv2, &calcpr, &xsize, &ysize, stream, &ymin, &ymax);
+    getopt_cleanup(argc, argv2);
+
+    if (stream != NULL)
+       fclose(stream);         /* plug potential malloc & file descriptor leak */
+
+    if (rc != -1) {
+        sprintf(dimensions, "%d %d", xsize, ysize);
+        Tcl_AppendResult(interp, dimensions, (char *) NULL);
         if (calcpr) {
 #if 0
            int i;
@@ -240,7 +478,6 @@ Rrd_Graph(clientData, interp, argc, argv)
             free(calcpr);
         }
     }
-    getopt_cleanup(argv, argv2);
 
     if (rrd_test_error()) {
        Tcl_AppendResult(interp, "RRD Error: ",
@@ -255,17 +492,13 @@ Rrd_Graph(clientData, interp, argc, argv)
 
 
 static int
-Rrd_Tune(clientData, interp, argc, argv)
-    ClientData clientData;
-    Tcl_Interp *interp;
-    int argc;
-    char *argv[];
+Rrd_Tune(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[])
 {
     char **argv2;
     
     argv2 = getopt_init(argc, argv);
     rrd_tune(argc, argv2);
-    getopt_cleanup(argv, argv2);
+    getopt_cleanup(argc, argv2);
 
     if (rrd_test_error()) {
        Tcl_AppendResult(interp, "RRD Error: ",
@@ -280,17 +513,13 @@ Rrd_Tune(clientData, interp, argc, argv)
 
 
 static int
-Rrd_Resize(clientData, interp, argc, argv)
-    ClientData clientData;
-    Tcl_Interp *interp;
-    int argc;
-    char *argv[];
+Rrd_Resize(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[])
 {
     char **argv2;
     
     argv2 = getopt_init(argc, argv);
     rrd_resize(argc, argv2);
-    getopt_cleanup(argv, argv2);
+    getopt_cleanup(argc, argv2);
 
     if (rrd_test_error()) {
        Tcl_AppendResult(interp, "RRD Error: ",
@@ -305,17 +534,13 @@ Rrd_Resize(clientData, interp, argc, argv)
 
 
 static int
-Rrd_Restore(clientData, interp, argc, argv)
-    ClientData clientData;
-    Tcl_Interp *interp;
-    int argc;
-    char *argv[];
+Rrd_Restore(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[])
 {
     char **argv2;
     
     argv2 = getopt_init(argc, argv);
     rrd_restore(argc, argv2);
-    getopt_cleanup(argv, argv2);
+    getopt_cleanup(argc, argv2);
 
     if (rrd_test_error()) {
        Tcl_AppendResult(interp, "RRD Error: ",
@@ -336,35 +561,46 @@ Rrd_Restore(clientData, interp, argc, argv)
 typedef struct {
     char *name;                        /* Name of the command. */
     Tcl_CmdProc *proc;         /* Procedure for command. */
+    int hide;                  /* Hide if safe interpreter */
 } CmdInfo;
 
 static CmdInfo rrdCmds[] = {
-    { "Rrd::create",   Rrd_Create              },
-    { "Rrd::dump",     Rrd_Dump                },
-    { "Rrd::last",     Rrd_Last                },
-    { "Rrd::update",   Rrd_Update              },
-    { "Rrd::fetch",    Rrd_Fetch               },
-    { "Rrd::graph",    Rrd_Graph               },
-    { "Rrd::tune",     Rrd_Tune                },
-    { "Rrd::resize",   Rrd_Resize              },
-    { "Rrd::restore",  Rrd_Restore             },
-    { (char *) NULL,   (Tcl_CmdProc *) NULL    }
+    { "Rrd::create",    Rrd_Create,     1 }, /* Thread-safe version */
+    { "Rrd::dump",      Rrd_Dump,       0 }, /* Thread-safe version */
+    { "Rrd::last",      Rrd_Last,       0 }, /* Thread-safe version */
+    { "Rrd::lastupdate", Rrd_Lastupdate, 0 }, /* Thread-safe version */
+    { "Rrd::update",    Rrd_Update,     1 }, /* Thread-safe version */
+    { "Rrd::fetch",     Rrd_Fetch,      0 },
+    { "Rrd::graph",     Rrd_Graph,      1 }, /* Due to RRD's API, a safe
+                                               interpreter cannot create
+                                               a graph since it writes to
+                                               a filename supplied by the
+                                               caller */
+    { "Rrd::tune",      Rrd_Tune,       1 },
+    { "Rrd::resize",    Rrd_Resize,     1 },
+    { "Rrd::restore",   Rrd_Restore,    1 },
+    { (char *) NULL,   (Tcl_CmdProc *)  NULL, 0        }
 };
 
 
 
-int
-Tclrrd_Init(interp, safe)
-    Tcl_Interp *interp;
-    int safe;
+static int
+init(Tcl_Interp *interp, int safe)
 { 
     CmdInfo *cmdInfoPtr;
     Tcl_CmdInfo info;
 
+    if ( Tcl_InitStubs(interp,TCL_VERSION,0) == NULL )
+       return TCL_ERROR;
+
     if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 1) == NULL) {
         return TCL_ERROR;
     }
 
+    /*
+     * Why a global array?  In keeping with the Rrd:: namespace, why
+     * not simply create a normal variable Rrd::version and set it?
+     */
     Tcl_SetVar2(interp, "rrd", "version", VERSION, TCL_GLOBAL_ONLY);
 
     for (cmdInfoPtr = rrdCmds; cmdInfoPtr->name != NULL; cmdInfoPtr++) {
@@ -378,7 +614,41 @@ Tclrrd_Init(interp, safe)
                             "\" already exists", (char *) NULL);
            return TCL_ERROR;
        }
-       Tcl_CreateCommand(interp, cmdInfoPtr->name, cmdInfoPtr->proc,
+       if (safe && cmdInfoPtr->hide) {
+#if 0
+           /*
+            * Turns out the one cannot hide a command in a namespace
+            * due to a limitation of Tcl, one can only hide global
+            * commands.  Thus, if we created the commands without
+            * the Rrd:: namespace in a safe interpreter, then the
+            * "unsafe" commands could be hidden -- which would allow
+            * an owning interpreter either un-hiding them or doing
+            * an "interp invokehidden".  If the Rrd:: namespace is
+            * used, then it's still possible for the owning interpreter
+            * to fake out the missing commands:
+            *
+            *   # Make all Rrd::* commands available in master interperter
+            *   package require Rrd
+            *   set safe [interp create -safe]
+            *   # Make safe Rrd::* commands available in safe interperter
+            *   interp invokehidden $safe -global load ./tclrrd1.2.11.so
+            *   # Provide the safe interpreter with the missing commands
+            *   $safe alias Rrd::update do_update $safe
+            *   proc do_update {which_interp $args} {
+            *     # Do some checking maybe...
+            *       :
+            *     return [eval Rrd::update $args]
+            *   }
+            *
+            * Our solution for now is to just not create the "unsafe"
+            * commands in a safe interpreter.
+            */
+           if (Tcl_HideCommand(interp, cmdInfoPtr->name, cmdInfoPtr->name) != TCL_OK)
+               return TCL_ERROR;
+#endif
+       }
+       else
+           Tcl_CreateCommand(interp, cmdInfoPtr->name, cmdInfoPtr->proc,
                          (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
     }
 
@@ -388,3 +658,20 @@ Tclrrd_Init(interp, safe)
 
     return TCL_OK;
 }
+
+int
+Tclrrd_Init(Tcl_Interp *interp)
+{ 
+  return init(interp, 0);
+}
+
+/*
+ * See the comments above and note how few commands are considered "safe"...
+ * Using rrdtool in a safe interpreter has very limited functionality.  It's
+ * tempting to just return TCL_ERROR and forget about it.
+ */
+int
+Tclrrd_SafeInit(Tcl_Interp *interp)
+{ 
+  return init(interp, 1);
+}
diff --git a/confignt/config.h b/confignt/config.h
deleted file mode 100644 (file)
index 7b9d68c..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/* config.h.nt: what configure _would_ say, if it ran on NT */
-
-#define STDC_HEADERS 1
-
-/* Define if you have the strftime function.  */
-#define HAVE_STRFTIME 1
-
-/* Define if you have the <math.h> header file.  */
-#define HAVE_MATH_H 1
-
-#define HAVE_SYS_TYPES_H 1
-#define HAVE_SYS_STAT_H 1
-
-#define rrd_realloc(a,b) realloc((a), (b))
-
-#define snprintf _snprintf
-/* Code in rrd_graph.c:rrd_graph_init() uses the %windir%
- * environment variable to override this. This should
- * avoid the recompile problem if the system directory is
- * c:/windows vs. d:/winnt.
- * This #define can't be removed because:
- * (1) the constant is used outside of rrd_graph_init() to init a struct
- * (2) windir might not be available in all environments
- */
-#define RRD_DEFAULT_FONT "c:/windows/fonts/cour.ttf"
-
-#define RRDGRAPH_YLEGEND_ANGLE 90.0
-
-#define HAVE_STRING_H 1
index 72c3a808319de7d51bbbabcff0f60c2b6a73f84e..09e026058c7e55b9273f38936f3c596ea7a09931 100644 (file)
@@ -4,12 +4,21 @@ dnl
 dnl Created by Jeff Allen, Tobi Oetiker, Blair Zajac
 dnl
 dnl Inspiration from http://autoconf-archive.cryp.to
-
 dnl tell automake the this script is for rrdtool
-AC_INIT([rrdtool],[1.1.9901])
+dnl the official version number is
+dnl a.b.c
+AC_INIT([rrdtool],[1.2.23])
+dnl for testing a numberical version number comes handy
+dnl the released version are
+dnl a.bccc
+dnl the devl versions will be something like
+dnl a.b999yymmddhh 
+NUMVERS=1.2023
+AC_SUBST(NUMVERS)
 AC_CANONICAL_TARGET
 AM_INIT_AUTOMAKE
-AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_HEADERS([rrd_config.h])
 
 dnl all our local stuff like install scripts and include files
 dnl is in there
@@ -17,10 +26,8 @@ dnl is in there
 
 dnl determine the type of system we are running on
 
-
 AC_SUBST(VERSION)
 
-dnl where we install our stuff ...
 AC_PREFIX_DEFAULT( /usr/local/rrdtool-$PACKAGE_VERSION )
 
 dnl Minimum Autoconf version required.
@@ -30,8 +37,8 @@ dnl At the TOP of the HEADER
 
 AH_TOP([
 
-#ifndef CONFIG_H
-#define CONFIG_H
+#ifndef RRD_CONFIG_H
+#define RRD_CONFIG_H
 /* IEEE can be prevented from raising signals with fpsetmask(0) */
 #undef MUST_DISABLE_FPMASK
 
@@ -45,11 +52,16 @@ AH_TOP([
  ])
 
 AH_BOTTOM([
+/* enable posix_fadvise on linux */
+#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_FCNTL_H)
+#define _XOPEN_SOURCE 600
+#include <fcntl.h>
+#endif
 
 /* define strrchr, strchr and memcpy, memmove in terms of bsd funcs
    make sure you are NOT using bcopy, index or rindex in the code */
       
-#if STDC_HEADERS
+#ifdef STDC_HEADERS
 # include <string.h>
 #else
 # ifndef HAVE_STRCHR
@@ -63,26 +75,29 @@ char *strchr (), *strrchr ();
 # endif
 #endif
 
-
-#if NO_NULL_REALLOC
+#ifdef NO_NULL_REALLOC
 # define rrd_realloc(a,b) ( (a) == NULL ? malloc( (b) ) : realloc( (a) , (b) ))
 #else
 # define rrd_realloc(a,b) realloc((a), (b))
-#endif      
+#endif
+
+#ifdef NEED_MALLOC_MALLOC_H
+#  include <malloc/malloc.h>
+#endif
 
-#if HAVE_MATH_H
+#ifdef HAVE_MATH_H
 #  include <math.h>
 #endif
 
-#if HAVE_FLOAT_H
+#ifdef HAVE_FLOAT_H
 #  include <float.h>
 #endif
 
-#if HAVE_IEEEFP_H
+#ifdef HAVE_IEEEFP_H
 #  include <ieeefp.h>
 #endif
 
-#if HAVE_FP_CLASS_H
+#ifdef HAVE_FP_CLASS_H
 #  include <fp_class.h>
 #endif
 
@@ -92,6 +107,12 @@ char *strchr (), *strrchr ();
 #  define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF)
 #endif
 
+/* solaris 10 it defines isnan such that only forte can compile it ... bad bad  */
+#if (defined(HAVE_ISNAN) && defined(isnan) && defined(HAVE_FPCLASS))
+#  undef isnan
+#  define isnan(a) (fpclass(a) == FP_SNAN || fpclass(a) == FP_QNAN)
+#endif
+
 /* for OSF1 Digital Unix */
 #if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H))
 #  define HAVE_ISINF 1
@@ -132,9 +153,45 @@ char *strchr (), *strrchr ();
 #error "Can't compile without isinf function"
 #endif
 
-#endif /* CONFIG_H */
+#endif /* RRD_CONFIG_H */
 ])
 
+dnl Process Special Options
+dnl -----------------------------------
+
+dnl How the vertical axis label is printed
+AC_ARG_VAR(RRDGRAPH_YLEGEND_ANGLE, 
+ [Vertical label angle: 90.0 (default) or 270.0])
+AC_DEFINE_UNQUOTED(RRDGRAPH_YLEGEND_ANGLE,${RRDGRAPH_YLEGEND_ANGLE:-90.0},
+ [Vertical label angle: 90.0 (default) or 270.0])
+
+AC_ARG_ENABLE(rrdcgi,[  --disable-rrdcgi        disable building of rrdcgi],
+[],[enable_rrdcgi=yes])
+
+dnl Check if we run on a system that has fonts
+AC_ARG_WITH(rrd-default-font,
+[  --with-rrd-default-font=[OPTIONS]  set the full path to your default font.],
+[RRD_DEFAULT_FONT=$withval],[
+  if test -d ${WINDIR:-nodir}/cour.ttf ; then
+       RRD_DEFAULT_FONT=`cd $WINDIR;pwd`/cour.ttf
+  else
+       RRD_DEFAULT_FONT='$(fontsdir)/$(fonts_DATA)'
+  fi
+])
+
+dnl Use mmap in rrd_update instead of seek+write
+AC_ARG_ENABLE([mmap],
+[  --disable-mmap          disable mmap in rrd_update, use seek+write instead],
+[],
+[enable_mmap=yes])
+
+
+ AC_ARG_ENABLE(pthread,[  --disable-pthread       disable multithread support],
+[],[enable_pthread=yes])
+
+
+
+CONFIGURE_PART(Audit Compilation Environment)
 
 
 dnl Check for the compiler and static/shared library creation.
@@ -142,10 +199,30 @@ AC_PROG_CC
 AC_PROG_CPP
 AC_PROG_LIBTOOL
 
+dnl which flags does the compile support?
+if test "$GCC" = "yes"; then
+  for flag in -fno-strict-aliasing -Wall -std=gnu99 -pedantic -Wshadow -Wpointer-arith -Wcast-align -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline -W; do
+    oCFLAGS=$CFLAGS
+    CFLAGS="$CFLAGS $flag"
+    cachename=rd_cv_gcc_flag_`echo $flag|sed 's/[[^A-Za-z]]/_/g'`
+    AC_CACHE_CHECK([if gcc likes the $flag flag], $cachename,
+       [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[return 0 ]])],[eval $cachename=yes],[eval $cachename=no])])
+    if eval test \$$cachename = no; then
+         CFLAGS=$oCFLAGS
+    fi
+  done
+fi
+
+
+
+AC_SUBST(RRD_DEFAULT_FONT)
+
+CONFIGURE_PART(Checking for Header Files)
 dnl Checks for header files.
 AC_HEADER_STDC
 AC_HEADER_DIRENT
-AC_CHECK_HEADERS(sys/stat.h sys/types.h fcntl.h time.h locale.h fp_class.h malloc.h unistd.h ieeefp.h math.h sys/time.h sys/times.h sys/param.h sys/resource.h float.h)
+AC_CHECK_HEADERS(sys/stat.h sys/types.h fcntl.h locale.h fp_class.h malloc.h unistd.h ieeefp.h math.h sys/times.h sys/param.h sys/resource.h float.h)
 
 dnl Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
@@ -159,6 +236,8 @@ dnl add pic flag in any case this makes sure all our code is relocatable
 eval `./libtool --config | grep pic_flag`
 CFLAGS="$CFLAGS $pic_flag"
 
+CONFIGURE_PART(Test Library Functions)
+
 dnl Checks for library functions.
 AC_FUNC_STRFTIME
 AC_FUNC_VPRINTF
@@ -168,57 +247,67 @@ AC_C_BIGENDIAN
 dnl for each function found we get a definition in config.h 
 dnl of the form HAVE_FUNCTION
 
-AC_CHECK_FUNCS(tzset opendir readdir chdir chroot getuid setlocale strerror strerror_r snprintf vsnprintf fpclass class fp_class isnan memmove strchr mktime getrusage gettimeofday)
+AC_CHECK_FUNCS(tzset mbstowcs opendir readdir chdir chroot getuid setlocale strerror strerror_r snprintf vsnprintf fpclass class fp_class isnan memmove strchr mktime getrusage gettimeofday posix_fadvise madvise)
 
-dnl Use mmap in rrd_update instead of seek+write
-AC_ARG_ENABLE([mmap],
-[  --disable-mmap          disable mmap in rrd_update, use seek+write instead],
-[],
-[enable_mmap=yes])
+AC_CHECK_DECLS(fdatasync, [], [], [#include <unistd.h>])
+AC_CHECK_DECLS(posix_fadvise, [], [], [#define _XOPEN_SOURCE 600
+#include <fcntl.h>])
+AC_CHECK_DECLS(madvise, [], [], [#include <sys/mman.h>])
 
 if test "x$enable_mmap" = xyes; then
-  AC_FUNC_MMAP
+  case "$host" in
+    *cygwin*)
+       # the normal mmap test does not work in cygwin
+       AC_CHECK_FUNCS(mmap)
+       if [ "x${ac_cv_func_mmap}" = xyes ]; then
+         ac_cv_func_mmap_fixed_mapped=yes
+       fi
+    ;;
+    *)
+       AC_FUNC_MMAP
+    ;;
+  esac
 fi
 
+
+CONFIGURE_PART(IEEE Math Checks)
 dnl HP-UX 11.00 does not have finite but does have isfinite as a macro so we need
 dnl actual code to check if this works
 AC_CHECK_FUNCS(fpclassify, ,
   [AC_MSG_CHECKING(for fpclassify with <math.h>)
-    AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <math.h>]], [[float f = 0.0; fpclassify(f)]])],[AC_MSG_RESULT(yes)
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <math.h>
+volatile int x;volatile float f; ]], [[x = fpclassify(f)]])],[AC_MSG_RESULT(yes)
       AC_DEFINE(HAVE_FPCLASSIFY)],[AC_MSG_RESULT(no)])])
 AC_CHECK_FUNCS(finite, ,
   [AC_CHECK_FUNCS(isfinite, ,
     [AC_MSG_CHECKING(for isfinite with <math.h>)
-    AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <math.h>]], [[float f = 0.0; isfinite(f)]])],[AC_MSG_RESULT(yes)
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <math.h>
+volatile int x;volatile float f;  ]], [[x = isfinite(f)]])],[AC_MSG_RESULT(yes)
       AC_DEFINE(HAVE_ISFINITE)],[AC_MSG_RESULT(no)])])])
 AC_CHECK_FUNCS(isinf, ,
   [AC_MSG_CHECKING(for isinf with <math.h>)
-    AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <math.h>]], [[float f = 0.0; isinf(f)]])],[AC_MSG_RESULT(yes)
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <math.h>
+volatile int x;volatile float f;  ]], [[x = isinf(f)]])],[AC_MSG_RESULT(yes)
       AC_DEFINE(HAVE_ISINF)],[AC_MSG_RESULT(no)])])
 
 AC_FULL_IEEE
 
-dnl How the vertical axis label is printed
-AC_ARG_VAR(RRDGRAPH_YLEGEND_ANGLE, 
- [Vertical label angle: 90.0 (default) or 270.0])
-AC_DEFINE_UNQUOTED(RRDGRAPH_YLEGEND_ANGLE,${RRDGRAPH_YLEGEND_ANGLE:-90.0},
- [Vertical label angle: 90.0 (default) or 270.0])
+CONFIGURE_PART(Resolve Portability Issues)
 
+dnl what does realloc do if it gets called with a NULL pointer
 
-AC_ARG_ENABLE(rrdcgi,[  --disable-rrdcgi        disable building of rrdcgi],
-[],[enable_rrdcgi=yes])
-AM_CONDITIONAL(BUILD_RRDCGI,[test $enable_rrdcgi != no])
-if test $enable_rrdcgi != no; then
-EX_CHECK_ALL(cgi,        cgiInit,                   cgi.h,                  cgilib,      0.5,    http://www.infodrom.org/projects/cgilib)
-fi
-EX_CHECK_ALL(art_lgpl_2, art_vpath_add_point,       libart_lgpl/libart.h,   libart-2.0,  2.3.17, ftp://ftp.gnome.org/pub/GNOME/sources/libart_lgpl/2.3/)
-EX_CHECK_ALL(z,          zlibVersion,               zlib.h,                 zlib,        1.2.1,  http://www.gzip.org/zlib/)
-EX_CHECK_ALL(png,        png_access_version_number, png.h,                  libpng,      1.2.8,  http://prdownloads.sourceforge.net/libpng/)
-EX_CHECK_ALL(freetype,   FT_Init_FreeType,          ft2build.h,                     freetype2,   2.1.9,  http://prdownloads.sourceforge.net/freetype/)
+AC_CACHE_CHECK([if realloc can deal with NULL], rd_cv_null_realloc,
+[AC_RUN_IFELSE([AC_LANG_SOURCE([[#include <stdlib.h>
+             int main(void){
+              char *x = NULL;
+             x = realloc (x,10);
+             if (x==NULL) return 1;
+             return 0;
+             }]])],[rd_cv_null_realloc=yes],[rd_cv_null_realloc=nope],[:])])
 
-if test "$EX_CHECK_ALL_ERR" = "YES"; then
-  AC_MSG_ERROR([Please fix the library issues listed above and try again.])
+if test x"$rd_cv_null_realloc" = xnope; then
+AC_DEFINE(NO_NULL_REALLOC)
 fi
 
 AC_LANG_PUSH(C)
@@ -244,7 +333,7 @@ AC_LINK_IFELSE(
                 [[#include <time.h>]],
                 [[ctime_r(NULL,NULL)]]
                         ),
-          [AC_MSG_RESULT(yes)],
+          [AC_MSG_RESULT(no)],
           [AC_MSG_ERROR([Can't figure how to compile ctime_r])]
       )
     ]  
@@ -257,11 +346,6 @@ dnl http://autoconf-archive.cryp.to/acx_pthread.m4
 AC_SUBST(MULTITHREAD_CFLAGS)
 AC_SUBST(MULTITHREAD_LDFLAGS)
 
-AC_ARG_ENABLE(pthread,[  --disable-pthread       disable multithread support],
-[],[enable_pthread=yes])
-
-
 if test $enable_pthread != no; then 
  ACX_PTHREAD([
     MULTITHREAD_CFLAGS=$PTHREAD_CFLAGS
@@ -277,40 +361,103 @@ if test  "x$x_rflag" != "xno"; then
    CPPFLAGS="$CPPFLAGS $x_rflag"
 fi
 
 AM_CONDITIONAL(BUILD_MULTITHREAD,[test $enable_pthread != no])
+
+AC_LANG_PUSH(C)
+dnl see if we have to include malloc/malloc.h
+AC_MSG_CHECKING([do we need malloc/malloc.h])
+AC_LINK_IFELSE(
+    AC_LANG_PROGRAM(
+           [[#include <stdlib.h>]],
+           [[malloc(1)]]
+                   ),
+    [ AC_MSG_RESULT([nope, works out of the box]) ],
+    [ AC_LINK_IFELSE(
+          AC_LANG_PROGRAM(
+                [[#include <stdlib.h>
+                  #include <malloc/malloc.h>]],
+                [[malloc(1)]]
+                        ),
+          [AC_DEFINE(NEED_MALLOC_MALLOC_H)
+           AC_MSG_RESULT([yes we do])],
+          [AC_MSG_ERROR([Can not figure how to compile malloc])]
+      )
+    ]  
+)
+AC_LANG_POP(C)
+
+CONFIGURE_PART(Find 3rd-Party Libraries)
+
+
+AM_CONDITIONAL(BUILD_RRDCGI,[test $enable_rrdcgi != no])
+
+CORE_LIBS="$LIBS"
+
+EX_CHECK_ALL(art_lgpl_2, art_vpath_add_point,       libart_lgpl/libart.h,   libart-2.0,  2.3.17, ftp://ftp.gnome.org/pub/GNOME/sources/libart_lgpl/2.3/, /usr/include/libart-2.0)
+EX_CHECK_ALL(z,          zlibVersion,               zlib.h,                 zlib,        1.2.3,  http://www.gzip.org/zlib/, "")
+EX_CHECK_ALL(png,        png_access_version_number, png.h,                  libpng,      1.2.10,  http://prdownloads.sourceforge.net/libpng/, "")
+EX_CHECK_ALL(freetype,   FT_Init_FreeType,          ft2build.h,                    freetype2,   2.1.10,  http://prdownloads.sourceforge.net/freetype/, /usr/include/freetype2)
+
+if test "$EX_CHECK_ALL_ERR" = "YES"; then
+  AC_MSG_ERROR([Please fix the library issues listed above and try again.])
+fi
+
+ALL_LIBS="$LIBS"
+LIBS=
+
+AC_SUBST(CORE_LIBS)
+AC_SUBST(ALL_LIBS)
+
+CONFIGURE_PART(Prep for Building Language Bindings)
   
 dnl Check for Perl.
 AC_PATH_PROG(PERL, perl, no)
-if test "x$PERL" = "xno"; then
+
+AC_ARG_ENABLE(perl,[  --disable-perl          do not build the perl modules],
+[],[enable_perl=yes])
+
+
+AC_ARG_VAR(PERLCC, [[] C compiler for Perl modules])
+AC_ARG_VAR(PERLCCFLAGS, [[] CC flags for Perl modules])
+AC_ARG_VAR(PERLLD, [[same as PERLCC] Linker for Perl modules])
+AC_ARG_VAR(PERLLDFLAGS, [[] LD flags for Perl modules])
+
+if test "x$PERL" = "xno" -o  x$enable_perl = xno; then
        COMP_PERL=
 else
        COMP_PERL="perl_piped perl_shared"
         AC_MSG_CHECKING(for the perl version you are running)
        PERL_VERSION=`$PERL -MConfig -e 'print $Config{version}'`
        AC_MSG_RESULT($PERL_VERSION)
-        AC_MSG_CHECKING(for the C compiler perl wants to use to build its modules)
-       perlcc=`$PERL -MConfig -e 'print $Config{cc}'`
-       AC_MSG_RESULT($perlcc)
-       if test ! -x $perlcc; then
-              AC_PATH_PROG(PERLCC, ${perlcc}, no)
-              if test -x $"x$PERLCC" = "xno"; then
-                  AC_MSG_WARN([
-I would not find the Compiler ($perlcc) that was originally used to compile your
-perl binary. You should either make sure that this compiler is available on your
-system, or use a different perl setup that was compiled with $CC.
-
-I will disable the compilation of the RRDs perl module.
+        if test -z "$PERLCC"; then
+            AC_MSG_CHECKING(for the C compiler perl wants to use to build its modules)
+           perlcc=`$PERL -MConfig -e 'print $Config{cc}'`
+           AC_MSG_RESULT($perlcc)
+           if test ! -x "$perlcc"; then
+               AC_PATH_PROG(PERL_CC, ${perlcc}, no)
+               if test "$PERL_CC" = "no"; then
+                    AC_MSG_WARN([
+I would not find the Compiler ($perlcc) that was originally used to compile
+your perl binary. You should either make sure that this compiler is
+available on your system, pick an other compiler and set PERLCC
+appropriately, or use a different perl setup that was compiled locally.
+
+I will disable the compilation of the RRDs perl module for now.
 ])
-                 COMP_PERL="perl_piped"
-              fi
+                   COMP_PERL="perl_piped"
+               fi
+            fi    
         fi
 fi
+
 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
-PERL_MAKE_OPTIONS="PREFIX=$prefix LIB=$prefix/lib/perl/$PERL_VERSION"
+ppref=$prefix
+test "$ppref" = "NONE" && ppref=$ac_default_prefix
+
+PERL_MAKE_OPTIONS="PREFIX=$ppref LIB=$ppref/lib/perl/$PERL_VERSION"
 
 dnl pass additional perl options when generating Makefile from Makefile.PL
 AC_ARG_ENABLE(perl-site-install,
@@ -322,6 +469,23 @@ AC_ARG_ENABLE(perl-site-install,
                           your perl setup thinks it is best.],
 [PERL_MAKE_OPTIONS=],[])
 
+if test ! -z "$PERLCC"; then
+   PERL_MAKE_OPTIONS="$PERL_MAKE_OPTIONS CC=$PERLCC"
+
+   if test ! -z "$PERLCCFLAGS"; then
+       PERL_MAKE_OPTIONS="$PERL_MAKE_OPTIONS CCFLAGS=$PERLCCFLAGS"
+   fi
+   
+   if test -z "$PERLLD"; then
+       PERLLD=$PERLCC
+   fi
+   PERL_MAKE_OPTIONS="$PERL_MAKE_OPTIONS LD=$PERLLD"
+  
+   if test ! -z "$PERLLDFLAGS"; then
+       PERL_MAKE_OPTIONS="$PERL_MAKE_OPTIONS LDFLAGS=$PERLLDFLAGS"
+   fi
+fi
+        
 AC_ARG_WITH(perl-options,
 [  --with-perl-options=[OPTIONS]  options to pass on command-line when
                           generating Makefile from Makefile.PL. If you set this
@@ -334,29 +498,84 @@ AC_SUBST(PERL)
 AC_SUBST(COMP_PERL)
 AC_SUBST(PERL_VERSION)
 
+dnl Check for Ruby.
+AC_PATH_PROG(RUBY, ruby, no)
+
+AC_ARG_ENABLE(ruby,[  --disable-ruby          do not build the ruby modules],
+[],[enable_ruby=yes])
+
+AC_MSG_CHECKING(if ruby modules can be built)
+
+if test "x$RUBY" = "xno" -o  x$enable_ruby = xno; then
+       COMP_RUBY=
+       AC_MSG_RESULT(No .. Ruby not found or disabled)
+else
+       if $RUBY -e 'require "mkmf"' >/dev/null 2>&1; then
+               COMP_RUBY="ruby"
+               AC_MSG_RESULT(YES)
+       else
+               COMP_RUBY=
+               AC_MSG_RESULT(Ruby found but mkmf is missing! Install the -dev package)         
+       fi                              
+fi
+
 
-dnl Check for Tcl.
-withval=""
-AC_ARG_WITH(tcllib,[  --with-tcllib=DIR       location of the tclConfig.sh])
-found=0
-AC_MSG_CHECKING(for tclConfig.sh in $withval)
-if test -f "$withval/tclConfig.sh" ; then
-       tcl_config=$withval/tclConfig.sh
-        found=1
+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
+                          for ruby to find the RRD.so file.],
+[RUBY_MAKE_OPTIONS=],[RUBY_MAKE_OPTIONS="sitedir=$prefix/lib/ruby"])
+
+    
+AC_ARG_WITH(ruby-options,
+[  --with-ruby-options=[OPTIONS]  options to pass on command-line when
+                          generating Makefile from extconf.rb. If you set this
+                          option, interesting things may happen unless you know
+                          what you are doing!],
+[RUBY_MAKE_OPTIONS=$withval])
+
+AC_SUBST(RUBY_MAKE_OPTIONS)
+AC_SUBST(RUBY)
+AC_SUBST(COMP_RUBY)
+
+
+enable_tcl_site=no
+
+AC_ARG_ENABLE(tcl,[  --disable-tcl           do not build the tcl modules],
+[],[enable_tcl=yes])
+
+if test  "$enable_tcl" = "yes"; then
+  dnl Check for Tcl.
+  withval=""
+  AC_ARG_WITH(tcllib,[  --with-tcllib=DIR       location of the tclConfig.sh])
+  enable_tcl=no
+  for dir in $withval /usr/lib /usr/local/lib; do
+    AC_MSG_CHECKING(for tclConfig.sh in $dir)
+    if test -f "$dir/tclConfig.sh" ; then
+       tcl_config=$dir/tclConfig.sh
+        enable_tcl=yes
         AC_MSG_RESULT(yes)
         break
-else
+    else
         AC_MSG_RESULT(no)
-fi
+    fi
+  done
 
-if test $found -eq 0 ; then
+  if test "$enable_tcl" = "no"; then
         AC_MSG_WARN([tclConfig.sh not found - Tcl interface won't be built])
-else
+  else
        . $tcl_config
-fi
+       TCL_PACKAGE_DIR="$TCL_PACKAGE_PATH/tclrrd$VERSION"
+  fi
+  AC_ARG_ENABLE(tcl,[  --enable-tcl-site        install the tcl extension in the tcl tree],
+  [],[enable_tcl_site=yes])
 
+fi
 
-AM_CONDITIONAL(COMP_TCL, test x$found = x1 )
+AM_CONDITIONAL(BUILD_TCL, test "$enable_tcl" = "yes" )
+AM_CONDITIONAL(BUILD_TCL_SITE, test "$enable_tcl_site" = "yes" )
 
 AC_SUBST(TCL_PREFIX)
 AC_SUBST(TCL_SHLIB_CFLAGS)
@@ -364,62 +583,60 @@ AC_SUBST(TCL_SHLIB_LD)
 AC_SUBST(TCL_SHLIB_SUFFIX)
 AC_SUBST(TCL_PACKAGE_PATH)
 AC_SUBST(TCL_LD_SEARCH_FLAGS)
+AC_SUBST(TCL_STUB_LIB_SPEC)
+AC_SUBST(TCL_VERSION)
+AC_SUBST(TCL_PACKAGE_DIR)
+
+AC_ARG_ENABLE(python,[  --disable-python        do not build the python modules],
+[],[enable_python=yes])
 
+if test  "$enable_python" = "yes"; then
+dnl Check for python
+AM_PATH_PYTHON(2.3,[],[enable_python=no])
+AM_CHECK_PYTHON_HEADERS(,[enable_python=no;AC_MSG_WARN(could not find Python headers)])
+fi
+
+if test  x$enable_python = xno; then
+       COMP_PYTHON=
+else
+       COMP_PYTHON="python"
+fi
 
+AC_SUBST(COMP_PYTHON)
 
 dnl Check for nroff
 AC_PATH_PROGS(NROFF, gnroff nroff)
 AC_PATH_PROGS(TROFF, groff troff)
 
-dnl Does the compiler like -Wall and -pedantic?
-if test "x$GCC" = "xyes"; then
-  oCFLAGS=$CFLAGS
-  CFLAGS="$CFLAGS -Wall -pedantic -Wshadow -Wpointer-arith -Wcast-align -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline -W"
-  AC_CACHE_CHECK(if we can use GCC-specific compiler options, rd_cv_gcc_opt,
-                [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[return 0 ]])],[rd_cv_gcc_opt=yes],[rd_cv_gcc_opt=no ])
-               ]
-        )
-  if test $rd_cv_gcc_opt = no; then
-         CFLAGS=$oCFLAGS
-  fi
-fi
+AC_ARG_VAR(RRDDOCDIR, [[DATADIR/doc/PACKAGE-VERSION] Documentation directory])
+if test -z "$RRDDOCDIR"; then
+   RRDDOCDIR='${datadir}/doc/${PACKAGE}-${VERSION}'; fi
 
-dnl what does realloc do if it gets called with a NULL pointer
 
-AC_CACHE_CHECK([if realloc can deal with NULL], rd_cv_null_realloc,
-[AC_RUN_IFELSE([AC_LANG_SOURCE([[#include <stdlib.h>
-             int main(void){
-              char *x = NULL;
-             x = realloc (x,10);
-             if (x==NULL) return 1;
-             return 0;
-             }]])],[rd_cv_null_realloc=yes],[rd_cv_null_realloc=nope],[:])])
-
-if test x"$rd_cv_null_realloc" = xnope; then
-AC_DEFINE(NO_NULL_REALLOC)
-fi
-
-AC_CONFIG_FILES([examples/shared-demo.pl                       \
-          examples/piped-demo.pl                       \
-          examples/stripes.pl                          \
-          examples/bigtops.pl                          \
-          examples/minmax.pl                           \
-          examples/cgi-demo.cgi                                \
-          examples/4charts.pl                                  \
-          examples/Makefile                            \
-          doc/Makefile                                 \
-          src/Makefile                                 \
-          bindings/Makefile                             \
-          bindings/tcl/Makefile                                \
-          Makefile])
-AC_CONFIG_COMMANDS([default],[[\
-          chmod +x examples/*.cgi examples/*.pl]],[[]])
+CONFIGURE_PART(Apply Configuration Information)
+AC_CONFIG_FILES([examples/shared-demo.pl])
+AC_CONFIG_FILES([examples/piped-demo.pl])
+AC_CONFIG_FILES([examples/stripes.pl])
+AC_CONFIG_FILES([examples/bigtops.pl])
+AC_CONFIG_FILES([examples/minmax.pl])
+AC_CONFIG_FILES([examples/4charts.pl])
+AC_CONFIG_FILES([examples/perftest.pl])
+AC_CONFIG_FILES([examples/Makefile])
+AC_CONFIG_FILES([doc/Makefile])
+AC_CONFIG_FILES([src/Makefile])
+AC_CONFIG_FILES([bindings/Makefile])
+AC_CONFIG_FILES([bindings/tcl/Makefile])
+AC_CONFIG_FILES([bindings/tcl/ifOctets.tcl])
+AC_CONFIG_FILES([Makefile])          
+
+AC_CONFIG_COMMANDS([default],[[ chmod +x examples/*.pl]],[[]])
 AC_OUTPUT
 
 AC_MSG_CHECKING(in)
 AC_MSG_RESULT(and out again)
 
-echo $ECHO_N "ordering CD from http://people.ee.ethz.ch/~oetiker/wish $ECHO_C" 1>&6
+echo $ECHO_N "ordering CD from http://tobi.oetiker.ch/wish $ECHO_C" 1>&6
 sleep 1
 echo $ECHO_N ".$ECHO_C" 1>&6
 sleep 1
@@ -434,21 +651,25 @@ echo
 echo "----------------------------------------------------------------"
 echo "Config is DONE!"
 echo
-echo "    With MMAP IO: $ac_cv_func_mmap_fixed_mapped"
-echo "    Perl Modules: $COMP_PERL"
-echo "     Perl Binary: $PERL"
-echo "    Perl Version: $PERL_VERSION"
-echo "    Perl Options: $PERL_MAKE_OPTIONS"
-echo "      Tcl Config: $tcl_config"
-echo "    Build rrdcgi: $enable_rrdcgi"
-echo " Build librrd MT: $enable_pthread"
+echo "          With MMAP IO: $ac_cv_func_mmap_fixed_mapped"
+echo "          Perl Modules: $COMP_PERL"
+echo "           Perl Binary: $PERL"
+echo "          Perl Version: $PERL_VERSION"
+echo "          Perl Options: $PERL_MAKE_OPTIONS"
+echo "          Ruby Modules: $COMP_RUBY"
+echo "           Ruby Binary: $RUBY"
+echo "          Ruby Options: $RUBY_MAKE_OPTIONS"
+echo "    Build Tcl Bindings: $enable_tcl"
+echo " Build Python Bindings: $enable_python"
+echo "          Build rrdcgi: $enable_rrdcgi"
+echo "       Build librrd MT: $enable_pthread"
+echo
 echo
-ech
 echo "Type 'make' to compile the software and use 'make install' to "
 echo "install everything to: $prefix."
 echo 
 echo "       ... that wishlist is NO JOKE. If you find RRDtool useful"
-echo "make me happy. Go to http://people.ee.ethz.ch/oetiker/wish and"
+echo "make me happy. Go to http://tobi.oetiker.ch/wish and"
 echo "place an order."
 echo 
 echo "                               -- Tobi Oetiker <tobi@oetiker.ch>"
index a6f32a9be5b2d030ac88983ae204d21373f1b7b7..4af7fb0b07e9ddc1e1525d082922c39260139e6e 100644 (file)
@@ -4,9 +4,9 @@ Fri, 10 Sep 1999 10:53:19 -0700.
 Copied from 1.0.46 to 1.1.0 snapshot by Mike Slifcak on Wed May 12 20:53:16 EDT 2004
 
 The source package was downloaded from 
-   http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/pub/beta/
+   http://oss.oetiker.ch/rrdtool/pub/
 
-Upstream Author(s): Tobias Oetiker <oetiker@ee.ethz.ch>
+Upstream Author(s): Tobias Oetiker <tobi@oetiker.ch>
 
 Modifications to upstream source:
        - Build and install shared libraries
index 9792b1fd91ea747d8340a01a43834b429d6f31d1..bf1b626cbb9e1a5d9cf8712b5ad1fe8412a60bcc 100644 (file)
@@ -1 +1 @@
-http://people.ee.ethz.ch       /~oetiker/webtools/rrdtool/pub  rrdtool-(.*)\.tar\.gz   debian
+http://oss.oetiker.ch  /rrdtool/pub    rrdtool-(.*)\.tar\.gz   debian
index d23f49f4bacf796019ac2da171d164b81a9aeafd..70f456c2a5a4f82db60c62dc601f06fc2a1e4c6b 100644 (file)
@@ -1,38 +1,34 @@
 ## Process this file with automake to produce Makefile.in
 
-SUFFIXES = .pod .1 .man .html .txt .pm .pdf .src .inc
+SUFFIXES = .pod .1 .man .html .txt .pm .pdf .inc
 
 #AUTOMAKE_OPTIONS        =  foreign
 
 #ACLOCAL_M4 = $(top_srcdir)/config/aclocal.m4
 
-CLEANFILES = *.1 *.html *.txt *-dircache *.pm *.pdf *~ core *itemcache *.rej *.orig rrdgraph_*.pod *.tmp rrdgraph.pod
+CLEANFILES = *.1 *.html *.txt *-dircache RRD?.pod *.pdf *~ core *itemcache *.rej *.orig *.tmp
 
-SRC = rrdgraph.src rrdgraph_examples.src  rrdgraph_rpn.src \
-      rrdgraph_data.src rrdgraph_graph.src
+POD = bin_dec_hex.pod        rrddump.pod            rrdgraph_examples.pod  rrdrestore.pod         rrdupdate.pod  \
+      cdeftutorial.pod       rrdfetch.pod           rrdgraph_graph.pod     rrdthreads.pod         rrdxport.pod   \
+      rpntutorial.pod        rrdfirst.pod           rrdgraph_rpn.pod       rrdtool.pod                           \
+      rrd-beginners.pod      rrdinfo.pod            rrdtune.pod            rrdbuild.pod                          \
+      rrdcgi.pod             rrdgraph.pod           rrdlast.pod            rrdlastupdate.pod                     \
+      rrdcreate.pod          rrdgraph_data.pod      rrdresize.pod          rrdtutorial.pod                       
 
-PODOLD = rrdgraph-old.pod
 
-POD = rrdtool.pod rrdlast.pod rrdfirst.pod rrdcreate.pod rrdupdate.pod  rrdtutorial.es.pod \
-       cdeftutorial.pod rpntutorial.pod rrdthreads.pod bin_dec_hex.pod \
-       rrdfetch.pod rrdrestore.pod rrddump.pod rrdtune.pod rrdresize.pod \
-       rrdcgi.pod rrdtutorial.pod rrdinfo.pod rrdxport.pod rrd-beginners.pod \
-       $(SRC:.src=.pod)
+PMP = RRDs.pod RRDp.pod
 
-PMP = RRDs.pm RRDp.pm
-
-MAN = $(POD:.pod=.1) $(PMP:.pm=.1)
+MAN = $(POD:.pod=.1)
 TXT = $(MAN:.1=.txt)
-HTML = $(POD:.pod=.html) $(PMP:.pm=.html)
+HTML = $(POD:.pod=.html) $(PMP:.pod=.html)
 PDF = $(MAN:.1=.pdf)
 
 # what should go into the distribution
-EXTRA_DIST= $(POD) $(HTML) $(TXT) rrdtool-dump.dtd rrdtool-xport.dtd
+EXTRA_DIST= $(POD) $(HTML) $(MAN) $(TXT) rrdtool-dump.dtd rrdtool-xport.dtd
 
-# some install rules
-idocdir = $(prefix)/doc
+idocdir = $(RRDDOCDIR)/txt
 idoc_DATA = $(POD) $(TXT)
-ihtmldir = $(prefix)/html
+ihtmldir = $(RRDDOCDIR)/html
 ihtml_DATA = $(HTML)
 imandir = $(mandir)/man1
 iman_DATA = $(MAN)
@@ -46,7 +42,7 @@ all-local: link txt man html-local
        pod2man --release=$(VERSION) --center=rrdtool $<  > $@
 
 .1.txt:
-       @NROFF@ -man -Tlp $< > $@
+       GROFF_NO_SGR=1 @NROFF@ -man -Tlp $< > $@
 
 .1.pdf:
        @TROFF@ -man $< | ps2pdf - $@
@@ -54,16 +50,13 @@ all-local: link txt man html-local
 .pm.html .pod.html .pl.html:
        pod2html --infile=$< --outfile=$@ --noindex --htmlroot=. --podpath=. --title=$*
 
-RRDs.pm:
-       ln -s ../bindings/perl-shared/RRDs.pm .
-
-RRDp.pm:
-       ln -s ../bindings/perl-piped/RRDp.pm .
+RRDs.pod:
+       $(LN_S) $(top_srcdir)/bindings/perl-shared/RRDs.pm RRDs.pod
 
-index.html:
-       rm -f index.html; ln -s rrdtool.html index.html
+RRDp.pod:
+       $(LN_S) $(top_srcdir)/bindings/perl-piped/RRDp.pm RRDp.pod
 
-link: RRDp.pm RRDs.pm index.html
+link: RRDp.pod RRDs.pod
 
 man: $(MAN)
 
@@ -73,3 +66,7 @@ txt: $(TXT)
 
 pdf-local: $(PDF)
 
+pod: $(POD)
+
+install-data-hook:
+       cd $(DESTDIR)$(ihtmldir) && rm -f index.html && $(LN_S) rrdtool.html index.html
index 3a2f2fbc2f8ca63c82e1fdc91381db189f080fd9..7a2adf5d2cfe7bc444e9b5ce257334df1eb3524a 100644 (file)
@@ -1,6 +1,6 @@
 =head1 NAME
 
-Binary Decimal Hexadecimal - How does it work
+bin_dec_hex - How to use binary, decimal, and hexadecimal notation.
 
 =for html <div align="right"><a href="bin_dec_hex.pdf">PDF</a> version.</div>
 
@@ -8,11 +8,11 @@ Binary Decimal Hexadecimal - How does it work
 
 Most people use the decimal numbering system. This system uses ten
 symbols to represent numbers. When those ten symbols are used up, they
-start all over again and increment the position just before this. The
+start all over again and increment the position to the left. The
 digit 0 is only shown if it is the only symbol in the sequence, or if
 it is not the first one.
 
-If this sounds cryptic to you, this is what I've said in numbers:
+If this sounds cryptic to you, this is what I've just said in numbers:
 
      0
      1
@@ -31,17 +31,21 @@ If this sounds cryptic to you, this is what I've said in numbers:
 
 and so on.
 
-Each time the digit nine should be incremented, it is reset to 0 and the
-position before is incremented. Then number 9 can be seen as "00009" and
-when we should increment 9, we reset it to zero and increment the digit
-just before the 9 so the number becomes "00010". For zero's we write a 
-space if it is not the only digit (so: number 0) and if it is the first
-digit: "00010" -> " 0010" -> "  010" -> "   10". It is not "   1 ".
+Each time the digit nine is incremented, it is reset to 0 and the
+position before (to the left) is incremented (from 0 to 1). Then
+number 9 can be seen as "00009" and when we should increment 9, we
+reset it to zero and increment the digit just before the 9 so the
+number becomes "00010". Leading zeros we don't write except if it is
+the only digit (number 0). And of course, we write zeros if they occur
+anywhere inside or at the end of a number:
 
-This was pretty basic, you already knew this. Why did I tell it ?
-Well, computers do not represent numbers with 10 different digits. They
-know of only two different symbols, being 0 and 1. Apply the same rules
-to this set of digits and you get the binary numbering system:
+ "00010" -> " 0010" -> " 010" -> "  10", but not "  1 ".
+
+This was pretty basic, you already knew this. Why did I tell it?
+Well, computers usually do not represent numbers with 10 different
+digits. They only use two different symbols, namely "0" and "1". Apply
+the same rules to this set of digits and you get the binary numbering
+system:
 
      0
      1
@@ -61,42 +65,47 @@ to this set of digits and you get the binary numbering system:
 and so on.
 
 If you count the number of rows, you'll see that these are again 14
-different numbers. The numbers are the same and mean the same. It is
-only a different representation. This means that you have to know the
-representation used, or as it is called the numbering system or base.
-Normally if we do not speak about the numbering system used, we're
-using the decimal system. If we are talking about another numbering
-system, we'll have to make that clear. There are a few wide-spread
-methods to do so. One common form is to write 1010(2) which means that
-you wrote down a number in the binary form. It is the number ten.
-If you would write 1010 it means the number one thousand and ten.
-
-In books, another form is most used. It uses subscript (little chars,
-more or less in between two rows). You can leave out the parentheses
-in that case and write down the number in normal characters followed
-with a little two just behind it.
-
-The numbering system used is also called the base. We talk of the number
-1100 base 2, the number 12 base 10.
-
-For the binary system, is is common to write leading zero's. The numbers
-are written down in series of four, eight or sixteen depending on the
-context.
-
-We can use the binary form when talking to computers (...programming...)
-but the numbers will have large representations. The number 65535 would
-be written down as 1111111111111111(2) which is 16 times the digit 1.
-This is difficult and prone to errors. Therefore we normally would use
+different numbers. The numbers are the same and mean the same as in
+the first list, we just used a different representation. This means
+that you have to know the representation used, or as it is called the
+numbering system or base.  Normally, if we do not explicitly specify
+the numbering system used, we implicitly use the decimal system. If we
+want to use any other numbering system, we'll have to make that
+clear. There are a few widely adopted methods to do so. One common
+form is to write 1010(2) which means that you wrote down a number in
+its binary representation. It is the number ten. If you would write
+1010 without specifying the base, the number is interpreted as one
+thousand and ten using base 10.
+
+In books, another form is common. It uses subscripts (little
+characters, more or less in between two rows). You can leave out the
+parentheses in that case and write down the number in normal
+characters followed by a little two just behind it.
+
+As the numbering system used is also called the base, we talk of the
+number 1100 base 2, the number 12 base 10.
+
+Within the binary system, it is common to write leading zeros. The
+numbers are written down in series of four, eight or sixteen depending
+on the context.
+
+We can use the binary form when talking to computers
+(...programming...), but the numbers will have large
+representations. The number 65'535 (often in the decimal system a ' is
+used to separate blocks of three digits for readability) would be
+written down as 1111111111111111(2) which is 16 times the digit 1.
+This is difficult and prone to errors. Therefore, we usually would use
 another base, called hexadecimal. It uses 16 different symbols. First
 the symbols from the decimal system are used, thereafter we continue
-with the alphabetic characters. We get 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A,
-B, C, D, E and F. This system is chosen because the hexadecimal form
-can be converted into the binary system very easy (and back).
+with alphabetic characters. We get 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+A, B, C, D, E and F. This system is chosen because the hexadecimal
+form can be converted into the binary system very easily (and back).
 
 There is yet another system in use, called the octal system. This was
-more common in the old days but not anymore. You will find it in use
-on some places so get used to it. The same story applies, but now with
-only eight different symbols.
+more common in the old days, but is not used very often anymore. As
+you might find it in use sometimes, you should get used to it and
+we'll show it below. It's the same story as with the other
+representations, but with eight different symbols.
 
  Binary      (2)
  Octal       (8)
@@ -106,7 +115,7 @@ only eight different symbols.
  (2)    (8) (10) (16)
  00000   0    0    0
  00001   1    1    1
- 00010   2    2    2 
+ 00010   2    2    2
  00011   3    3    3
  00100   4    4    4
  00101   5    5    5
@@ -129,7 +138,7 @@ only eight different symbols.
 
 Most computers used nowadays are using bytes of eight bits. This means
 that they store eight bits at a time. You can see why the octal system
-is not the most preferred for that: You'd need three digits to represent
+is not the most practical for that: You'd need three digits to represent
 the eight bits and this means that you'd have to use one complete digit
 to represent only two bits (2+3+3=8). This is a waste. For hexadecimal
 digits, you need only two digits which are used completely:
@@ -137,29 +146,28 @@ digits, you need only two digits which are used completely:
  (2)      (8)  (10) (16)
  11111111 377  255   FF
 
-You can see why binary and hexadecimal can be converted quickly:
-For each hexadecimal digit there are exactly four binary digits.
-Take a binary number. Each time take four digits from the right and make
-a hexadecimal digit from it (see the table above). Stop when there are
-no more digits.
-Other way around: Take a hexadecimal number. For each digit, write down
-its binary equivalent.
-
-Computers (or rather the parsers running on them) would have a hard time
-converting a number like 1234(16). Therefore hexadecimal numbers get a
-prefix. This prefix depends on the language you're writing in. Some of
-the prefixes are "0x" for C, "$" for Pascal, "#" for HTML.
-It is common to assume that if a number starts with a zero, it is octal.
-It does not matter what is used as long as you know what it is.
-I will use "0x" for hexadecimal, "%" for binary and "0" for octal.
-The following numbers are all the same, just the way they are written is
-different:  021  0x11  17  %00010001
+You can see why binary and hexadecimal can be converted quickly: For
+each hexadecimal digit there are exactly four binary digits.  Take a
+binary number: take four digits from the right and make a hexadecimal
+digit from it (see the table above). Repeat this until there are no
+more digits. And the other way around: Take a hexadecimal number. For
+each digit, write down its binary equivalent.
+
+Computers (or rather the parsers running on them) would have a hard
+time converting a number like 1234(16). Therefore hexadecimal numbers
+are specified with a prefix. This prefix depends on the language
+you're writing in. Some of the prefixes are "0x" for C, "$" for
+Pascal, "#" for HTML.  It is common to assume that if a number starts
+with a zero, it is octal. It does not matter what is used as long as
+you know what it is. I will use "0x" for hexadecimal, "%" for binary
+and "0" for octal.  The following numbers are all the same, just their represenatation (base) is different: 021 0x11 17 %00010001
 
 To do arithmetics and conversions you need to understand one more thing.
 It is something you already know but perhaps you do not "see" it yet:
 
-If you write down 1234, (so it is decimal) you are talking about the
-number one thousand, two hundred and thirty four. In sort of a formula:
+If you write down 1234, (no prefix, so it is decimal) you are talking
+about the number one thousand, two hundred and thirty four. In sort of
+a formula:
 
  1 * 1000 = 1000
  2 *  100 =  200
@@ -197,7 +205,7 @@ It is the same in all other representations:
  3 * 8^1
  4 * 8^0
 
-This example can not be done for binary as that system can only use two
+This example can not be done for binary as that system only uses two
 symbols. Another example:
 
 %1010 would be
@@ -207,69 +215,68 @@ symbols. Another example:
  1 * 2^1
  0 * 2^0
 
-It would have been more easy to convert it to its hexadecimal form and
+It would have been easier to convert it to its hexadecimal form and
 just translate %1010 into 0xA. After a while you get used to it. You will
-not need to do any calculations anymore but just know that 0xA means 10.
+not need to do any calculations anymore, but just know that 0xA means 10.
 
-To convert a decimal number into a hexadecimal one you could use the next
-method. It will take some time to be able to do the estimates but it will
-be more and more easy when you use the system more frequent. Another way
-is presented to you thereafter.
+To convert a decimal number into a hexadecimal you could use the next
+method. It will take some time to be able to do the estimates, but it
+will be easier when you use the system more frequently. We'll look at
+yet another way afterwards.
 
-First you will need to know how many positions will be used in the other
-system. To do so, you need to know the maximum numbers. Well, that's not
-so hard as it looks. In decimal, the maximum number that you can form 
-with two digits is "99". The maximum for three: "999". The next number
-would need an extra position. Reverse this idea and you will see that
-the number can be found by taking 10^3 (10*10*10 is 1000) minus 1 or
-10^2 minus one.
+First you need to know how many positions will be used in the other
+system. To do so, you need to know the maximum numbers you'll be
+using. Well, that's not as hard as it looks. In decimal, the maximum
+number that you can form with two digits is "99". The maximum for
+three: "999". The next number would need an extra position. Reverse
+this idea and you will see that the number can be found by taking 10^3
+(10*10*10 is 1000) minus 1 or 10^2 minus one.
 
-This can be done for hexadecimal too:
+This can be done for hexadecimal as well:
 
  16^4 = 0x10000 = 65536
  16^3 =  0x1000 =  4096
  16^2 =   0x100 =   256
  16^1 =    0x10 =    16
 
-If a number is smaller than 65536 it will thus fit in four positions.
-If the number is bigger than 4095, you will need to use position 4.
-How many times can you take 4096 from the number without going below
+If a number is smaller than 65'536 it will fit in four positions.
+If the number is bigger than 4'095, you must use position 4.
+How many times you can subtract 4'096 from the number without going below
 zero is the first digit you write down. This will always be a number
 from 1 to 15 (0x1 to 0xF). Do the same for the other positions.
 
-Number is 41029. It is smaller than 16^4 but bigger than 16^3-1. This
+Let's try with 41'029. It is smaller than 16^4 but bigger than 16^3-1. This
 means that we have to use four positions.
-We can subtract 16^3 from 41029 ten times without going below zero.
-The leftmost digit will be "A" so we have 0xA????.
-The number is reduced to 41029 - 10*4096 = 41029-40960 = 69.
+We can subtract 16^3 from 41'029 ten times without going below zero.
+The left-most digit will therefore be "A", so we have 0xA????.
+The number is reduced to 41'029 - 10*4'096 = 41'029-40'960 = 69.
 69 is smaller than 16^3 but not bigger than 16^2-1. The second digit
-is therefore "0" and we know 0xA0??.
+is therefore "0" and we now have 0xA0??.
 69 is smaller than 16^2 and bigger than 16^1-1. We can subtract 16^1
 (which is just plain 16) four times and write down "4" to get 0xA04?.
-Take 64 from 69 (69 - 4*16) and the last digit is 5 --> 0xA045.
+Subtract 64 from 69 (69 - 4*16) and the last digit is 5 --> 0xA045.
 
-The other method builds the number from the right. Take again 41029.
-Divide by 16 and do not use fractions (only whole numbers).
+The other method builds ub the number from the right. Let's try 41'029
+again.  Divide by 16 and do not use fractions (only whole numbers).
 
- 41029 / 16 is 2564 with a remainder of 5. Write down 5.
- 2564 / 16 is 160 with a remainder of 4. Write the 4 before the 5.
+ 41'029 / 16 is 2'564 with a remainder of 5. Write down 5.
+ 2'564 / 16 is 160 with a remainder of 4. Write the 4 before the 5.
  160 / 16 is 10 with no remainder. Prepend 45 with 0.
  10 / 16 is below one. End here and prepend 0xA. End up with 0xA045.
 
-Which method to use is up to you. Use whatever works for you. Personally
-I use them both without being able to tell what method I use in each
-case, it just depends on the number, I think. Fact is, some numbers
-will occur frequently while programming, if the number is close then
-I will use the first method (like 32770, translate into 32768 + 2 and
-just know that it is 0x8000 + 0x2 = 0x8002).
-
+Which method to use is up to you. Use whatever works for you.  I use
+them both without being able to tell what method I use in each case,
+it just depends on the number, I think. Fact is, some numbers will
+occur frequently while programming. If the number is close to one I am
+familiar with, then I will use the first method (like 32'770 which is
+into 32'768 + 2 and I just know that it is 0x8000 + 0x2 = 0x8002).
 
 For binary the same approach can be used. The base is 2 and not 16,
 and the number of positions will grow rapidly. Using the second method
-has the advantage that you can see very simple if you should write down
+has the advantage that you can see very easily if you should write down
 a zero or a one: if you divide by two the remainder will be zero if it
-was an even number and one if it was an odd number:
+is an even number and one if it is an odd number:
+
  41029 / 2 = 20514 remainder 1
  20514 / 2 = 10257 remainder 0
  10257 / 2 =  5128 remainder 1
@@ -317,10 +324,10 @@ Group %1010000001000101 by three and convert into octal:
 At first while adding numbers, you'll convert them to their decimal
 form and then back into their original form after doing the addition.
 If you use the other numbering system often, you will see that you'll
-be able to do arithmetics in the base that is used.
+be able to do arithmetics directly in the base that is used.
 In any representation it is the same, add the numbers on the right,
-write down the rightmost digit from the result, remember the other
-digits and use them in the next round. Continue with the second digits
+write down the right-most digit from the result, remember the other
+digits and use them in the next round. Continue with the second digit
 from the right and so on:
 
     %1010 + %0111 --> 10 + 7 --> 17 --> %00010001
@@ -338,16 +345,16 @@ will become
  --------
    %10001 is the result, I like to write it as %00010001
 
-For low values, try to do the calculations yourself, check them with
-a calculator. The more you do the calculations yourself, the more you
+For low values, try to do the calculations yourself, then check them with
+a calculator. The more you do the calculations yourself, the more you'll
 find that you didn't make mistakes. In the end, you'll do calculi in
-other bases as easy as you do in decimal.
+other bases as easily as you do them in decimal.
 
 When the numbers get bigger, you'll have to realize that a computer is
-not called a computer just to have a nice name. There are many different
-calculators available. Use them. For Unix you could use "bc" which is
-called so as it is short for Binary Calculator. It calculates not only
-in decimal, but in all bases you'll ever use (among them Binary).
+not called a computer just to have a nice name. There are many
+different calculators available, use them. For Unix you could use "bc"
+which is short for Binary Calculator. It calculates not only in
+decimal, but in all bases you'll ever want to use (among them Binary).
 
 For people on Windows:
 Start the calculator (start->programs->accessories->calculator)
@@ -358,8 +365,7 @@ calculator and can compute in binary or hexadecimal.
 
 I hope you enjoyed the examples and their descriptions. If you do, help
 other people by pointing them to this document when they are asking
-basic questions. They will not only get their answer but at the same
+basic questions. They will not only get their answer, but at the same
 time learn a whole lot more.
 
-Alex van den Bogaerdt 
-<alex@ergens.op.het.net>
+Alex van den Bogaerdt  E<lt>alex@ergens.op.het.netE<gt>
index fb337702a3669b88043d7c38c31c211c1dd08349..6a45ef4a0d4fcf5aa1e9288ba7bc3ec1d1960e1c 100644 (file)
@@ -2,21 +2,22 @@
 
 cdeftutorial - Alex van den Bogaerdt's CDEF tutorial
 
-=for html <div align="right"><a href="cdeftutorial.pdf">PDF</a> version.</div> 
-
 =head1 DESCRIPTION
 
-B<You provide a question and I will try to provide an answer in the next
-release>. B<No feedback equals no changes!>
-
-I<Additions to this document are also welcome.>
+Intention of this document: to provide some examples of the commonly
+used parts of RRDtool's CDEF language.
 
-Alex van den Bogaerdt E<lt>alex@ergens.op.het.netE<gt>
+If you think some important feature is not explained properly, and if
+adding it to this document would benefit most users, please do ask me
+to add it.  I will then try to provide an answer in the next release
+of this tutorial.  No feedback equals no changes! Additions to
+this document are also welcome.  -- Alex van den Bogaerdt
+E<lt>alex@ergens.op.het.netE<gt>
 
-=head2 Why this tutorial ?
+=head2 Why this tutorial?
 
 One of the powerful parts of RRDtool is its ability to do all sorts
-of calculations on the data retrieved from it's databases. However
+of calculations on the data retrieved from its databases. However,
 RRDtool's many options and syntax make it difficult for the average
 user to understand. The manuals are good at explaining what these
 options do; however they do not (and should not) explain in detail
@@ -25,14 +26,14 @@ simple document in simple language you should read this tutorial.
 If you are happy with the official documentation, you may find this
 document too simple or even boring. If you do choose to read this
 tutorial, I also expect you to have read and fully understand my
-other tutorial. 
+other tutorial.
 
 =head2 More reading
 
 If you have difficulties with the way I try to explain it please read
 Steve Rader's L<rpntutorial>. It may help you understand how this all works.
 
-=head1 What are CDEFs ?
+=head1 What are CDEFs?
 
 When retrieving data from an RRD, you are using a "DEF" to work with
 that data. Think of it as a variable that changes over time (where
@@ -62,12 +63,12 @@ instead of the original:
 
    CDEF:inbits=inbytes,8,*
 
-It tells to multiply inbytes by eight to get inbits. I'll explain later
-how this works. In the graphing or printing functions, you can now use
-inbits where you would use inbytes otherwise.
+This tells RRDtool to multiply inbytes by eight to get inbits. I'll
+explain later how this works. In the graphing or printing functions,
+you can now use inbits where you would use inbytes otherwise.
 
-Note that variable in the CDEF (inbits) must not be the same as the
-variable (inbytes) in the DEF!
+Note that the variable name used in the CDEF (inbits) must not be the
+same as the variable named in the DEF (inbytes)!
 
 =head1 RPN-expressions
 
@@ -137,20 +138,20 @@ inbytes would have value 10, the stack would be:
 
 ||
 
-=back 
+=back
 
 Processing the stack (step 5) will retrieve one value from the stack
 (from the right at step 4). This is the operation multiply and this
 takes two values off the stack as input. The result is put back on the
 stack (the value 80 in this case). For multiplication the order doesn't
-matter but for other operations like subtraction and division it does.
+matter, but for other operations like subtraction and division it does.
 Generally speaking you have the following order:
 
    y = A - B  -->  y=minus(A,B)  -->  CDEF:y=A,B,-
 
 This is not very intuitive (at least most people don't think so). For
-the function f(A,B) you reverse the position of "f" but you do not
-reverse the order of the variables. 
+the function f(A,B) you reverse the position of "f", but you do not
+reverse the order of the variables.
 
 =head1 Converting your wishes to RPN
 
@@ -178,7 +179,7 @@ RRD router1.rrd)
    router1.rrd:link2in
    router2.rrd:link1in
    router3.rrd:link1in
-   router3.rrd:link2in 
+   router3.rrd:link2in
    --------------------   +
    (outcome of the sum)
 
@@ -216,7 +217,7 @@ This is correct but it can be made more clear to humans. It does
 not matter if you add a to b and then add c to the result or first
 add b to c and then add a to the result. This makes it possible to
 rewrite the RPN into C<CDEF:result=a,b,c,d,e,+,+,+,+> which is
-evaluated differently: 
+evaluated differently:
 
    push value of variable a on the stack: a
    push value of variable b on the stack: a b
@@ -233,17 +234,17 @@ evaluated differently:
    and process it:                        S         (where S == a+R)
 
 As you can see the RPN expression C<a,b,c,d,e,+,+,+,+,+> will evaluate in
-C<((((d+e)+c)+b)+a)> and it has the same outcome as C<a,b,+,c,+,d,+,e,+> 
-According to Steve Rader this is called the commutative law of addition
+C<((((d+e)+c)+b)+a)> and it has the same outcome as C<a,b,+,c,+,d,+,e,+>.
+This is called the commutative law of addition,
 but you may forget this right away, as long as you remember what it
-represents.
+means.
 
 Now look at an expression that contains a multiplication:
 
 First in normal math: C<let result = a+b*c>. In this case you can't
 choose the order yourself, you have to start with the multiplication
-and then add a to it. You may alter the position of b and c, you may
-not alter the position of a and b. 
+and then add a to it. You may alter the position of b and c, you must
+not alter the position of a and b.
 
 You have to take this in consideration when converting this expression
 into RPN. Read it as: "Add the outcome of b*c to a" and then it is
@@ -257,8 +258,8 @@ easy to write it in RPN: C<result=a,b,c,+,*>. Note that this is very
 similar to one of the expressions in the previous paragraph, only the
 multiplication and the addition changed places.
 
-When you have problems with RPN or when RRDtool is complaining, it's 
-usually a Good Thing to write down the stack on a piece of paper
+When you have problems with RPN or when RRDtool is complaining, it's
+usually a good thing to write down the stack on a piece of paper
 and see what happens. Have the manual ready and pretend to be RRDtool.
 Just do all the math by hand to see what happens, I'm sure this will
 solve most, if not all, problems you encounter.
@@ -269,7 +270,7 @@ solve most, if not all, problems you encounter.
 
 Sometimes collecting your data will fail. This can be very common,
 especially when querying over busy links. RRDtool can be configured
-to allow for one (or even more) unknown value and calculate the missing
+to allow for one (or even more) unknown value(s) and calculate the missing
 update. You can, for instance, query your device every minute. This is
 creating one so called PDP or primary data point per minute. If you
 defined your RRD to contain an RRA that stores 5-minute values, you need
@@ -280,7 +281,7 @@ These PDPs can become unknown in two cases:
 
 =item 1.
 
-The updates are too far apart. This is tuned using the "heartbeat" setting
+The updates are too far apart. This is tuned using the "heartbeat" setting.
 
 =item 2.
 
@@ -299,12 +300,12 @@ Suppose the counter increments with one per second and you retrieve it
 every minute:
 
    counter value    resulting rate
-   10000
-   10060            1; (10060-10000)/60 == 1
-   10120            1; (10120-10060)/60 == 1
-   unknown          unknown; you don't know the last value
-   10240            unknown; you don't know the previous value
-   10300            1; (10300-10240)/60 == 1
+   10'000
+   10'060            1; (10'060-10'000)/60 == 1
+   10'120            1; (10'120-10'060)/60 == 1
+   unknown           unknown; you don't know the last value
+   10'240            unknown; you don't know the previous value
+   10'300            1; (10'300-10'240)/60 == 1
 
 If the CDP was to be calculated from the last five updates, it would get
 two unknown PDPs and three known PDPs. If xff would have been set to 0.5
@@ -340,14 +341,14 @@ data into zero. The counters of the device were unknown (after all, it
 wasn't installed yet!) but you know that the data rate through the device
 had to be zero (because of the same reason: it was not installed).
 
-There are some examples further on that make this change.
+There are some examples below that make this change.
 
 =head2 Infinity
 
-Infinite data is another form of a special number. It cannot be graphed
-because by definition you would never reach the infinite value. You could
-think of positive and negative infinity (I'm not sure if mathematicians
-will agree) depending on the position relative to zero.
+Infinite data is another form of a special number. It cannot be
+graphed because by definition you would never reach the infinite
+value. You can think of positive and negative infinity depending on
+the position relative to zero.
 
 RRDtool is capable of representing (-not- graphing!) infinity by stopping
 at its current maximum (for positive infinity) or minimum (for negative
@@ -389,14 +390,14 @@ the other database.
 
 =item *
 
-Alternately you could use CDEF and alter unknown data to zero.
+Alternatively, you could use CDEF and alter unknown data to zero.
 
 =back
 
 Both methods have their pros and cons. The first method is troublesome and
 if you want to do that you have to figure it out yourself. It is not
 possible to create a database filled with zeros, you have to put them in
-on purpose. Implementing the second method is described next:
+manually. Implementing the second method is described next:
 
 What we want is: "if the value is unknown, replace it with zero". This
 could be written in pseudo-code as:  if (value is unknown) then (zero)
@@ -448,7 +449,7 @@ to remove this rule so that unknown data is properly displayed.
 
 =head2 Example: better handling of unknown data, by using time
 
-Above example has one drawback. If you do log unknown data in
+The above example has one drawback. If you do log unknown data in
 your database after installing your new equipment, it will also be
 translated into zero and therefore you won't see that there was a
 problem. This is not good and what you really want to do is:
@@ -457,28 +458,28 @@ problem. This is not good and what you really want to do is:
 
 =item *
 
-If there is unknown data, look at the time that this sample was taken
+If there is unknown data, look at the time that this sample was taken.
 
 =item *
 
-If the unknown value is before time xxx, make it zero
+If the unknown value is before time xxx, make it zero.
 
 =item *
 
-If it is after time xxx, leave it as unknown data
+If it is after time xxx, leave it as unknown data.
 
 =back
 
 This is doable: you can compare the time that the sample was taken
 to some known time. Assuming you started to monitor your device on
-Friday September 17, 00:35:57 MET DST. Translate this time in seconds
-since 1970-01-01 and it becomes 937521357. If you process unknown values
+Friday September 17, 1999, 00:35:57 MET DST. Translate this time in seconds
+since 1970-01-01 and it becomes 937'521'357. If you process unknown values
 that were received after this time, you want to leave them unknown and
 if they were "received" before this time, you want to translate them
 into zero (so you can effectively ignore them while adding them to your
 other routers counters).
 
-Translating Friday September 17, 00:35:57 MET DST into 937521357 can
+Translating Friday September 17, 1999, 00:35:57 MET DST into 937'521'357 can
 be done by, for instance, using gnu date:
 
    date -d "19990917 00:35:57" +%s
@@ -494,11 +495,11 @@ This is a three step process:
 
 =item 1.
 
-If the timestamp of the value is after 937521357, leave it as is
+If the timestamp of the value is after 937'521'357, leave it as is.
 
 =item 2.
 
-If the value is a known value, leave it as is
+If the value is a known value, leave it as is.
 
 =item 3.
 
@@ -529,7 +530,7 @@ so lets do it quick:
       where x represents "time>937521357"
       where a represents the original value
       where b represents the outcome of the previous example
-      
+
    time>937521357       --> TIME,937521357,GT
 
    if (x) then a else b --> x,a,b,IF
@@ -540,13 +541,13 @@ so lets do it quick:
 We end up with:
 C<CDEF:result=TIME,937521357,GT,value,value,UN,0,value,IF,IF>
 
-This looks very complex however as you can see it was not too hard to
+This looks very complex, however, as you can see, it was not too hard to
 come up with.
 
 =head2 Example: Pretending weird data isn't there
 
 Suppose you have a problem that shows up as huge spikes in your graph.
-You know this happens and why so you decide to work around the problem.
+You know this happens and why, so you decide to work around the problem.
 Perhaps you're using your network to do a backup at night and by doing
 so you get almost 10mb/s while the rest of your network activity does
 not produce numbers higher than 100kb/s.
@@ -558,11 +559,11 @@ There are two options:
 =item 1.
 
 If the number exceeds 100kb/s it is wrong and you want it masked out
-by changing it into unknown
+by changing it into unknown.
 
 =item 2.
 
-You don't want the graph to show more than 100kb/s
+You don't want the graph to show more than 100kb/s.
 
 =back
 
@@ -578,7 +579,7 @@ the numbers to display maxima they will be set to 100kb/s.
 We use "IF" and "GT" again. "if (x) then (y) else (z)" is written
 down as "CDEF:result=x,y,z,IF"; now fill in x, y and z.
 For x you fill in "number greater than 100kb/s" becoming
-"number,100000,GT" (kilo is 1000 and b/s is what we measure!).
+"number,100000,GT" (kilo is 1'000 and b/s is what we measure!).
 The "z" part is "number" in both cases and the "y" part is either
 "UNKN" for unknown or "100000" for 100kb/s.
 
@@ -590,7 +591,7 @@ The two CDEF expressions would be:
 =head2 Example: working on a certain time span
 
 If you want a graph that spans a few weeks, but would only want to
-see some routers data for one week, you need to "hide" the rest of
+see some routers' data for one week, you need to "hide" the rest of
 the time frame. Don't ask me when this would be useful, it's just
 here for the example :)
 
@@ -700,11 +701,11 @@ if you like.  But there are good reasons for writing two CDEFS:
 
 =item *
 
-It improves the readability of the script
+It improves the readability of the script.
 
 =item *
 
-It can be used inside GPRINT to display the total number of users
+It can be used inside GPRINT to display the total number of users.
 
 =back
 
@@ -725,9 +726,12 @@ If you do so, you won't be able to use these next GPRINTs:
 
 =head2 Degrees Celsius vs. Degrees Fahrenheit
 
+To convert Celsius into Fahrenheit use the formula
+F=9/5*C+32
+
    rrdtool graph demo.png --title="Demo Graph" \
       DEF:cel=demo.rrd:exhaust:AVERAGE \
-      CDEF:far=cel,32,-,0.55555,* \
+      CDEF:far=9,5,/,cel,*,32,+ \
       LINE2:cel#00a000:"D. Celsius" \
       LINE2:far#ff0000:"D. Fahrenheit\c"
 
@@ -735,19 +739,17 @@ This example gets the DS called "exhaust" from database "demo.rrd"
 and puts the values in variable "cel". The CDEF used is evaluated
 as follows:
 
-   CDEF:far=cel,32,-,0.5555,*
-   1. push variable "cel"
-   2. push 32
-   3. push function "minus" and process it
-      The stack now contains values that are 32 less than "cel"
-   4. push 0.5555
-   5. push function "multiply" and process it
-   6. the resulting value is now "(cel-32)*0.55555"
-
-Note that if you take the Celsius to Fahrenheit function you should
-be doing "5/9*(cel-32)" so 0.55555 is not exactly correct. It is close
-enough for this purpose and it saves a calculation.
-
+   CDEF:far=9,5,/,cel,*,32,+
+   1. push 9, push 5
+   2. push function "divide" and process it
+      the stack now contains 9/5
+   3. push variable "cel"
+   4. push function "multiply" and process it
+      the stack now contains 9/5*cel
+   5. push 32
+   6. push function "plus" and process it
+      the stack contains now the temperature in Fahrenheit
+   
 =head2 Changing unknown into zero
 
    rrdtool graph demo.png --title="Demo Graph" \
@@ -760,13 +762,15 @@ enough for this purpose and it saves a calculation.
       AREA:agginput#00cc00:Input Aggregate \
       LINE1:aggoutput#0000FF:Output Aggregate
 
-These two CDEFs are built from several functions. It helps to
-split them when viewing what they do.
-Starting with the first CDEF we would get:
-      idat1,UN --> a
-      0        --> b
-      idat1    --> c
-      if (a) then (b) else (c)
+These two CDEFs are built from several functions. It helps to split
+them when viewing what they do. Starting with the first CDEF we would
+get:
+
+ idat1,UN --> a
+ 0        --> b
+ idat1    --> c
+ if (a) then (b) else (c)
+
 The result is therefore "0" if it is true that "idat1" equals "UN".
 If not, the original value of "idat1" is put back on the stack.
 Lets call this answer "d". The process is repeated for the next
@@ -802,10 +806,10 @@ to see what happens in the "background" CDEF.
 
 This RPN takes the value of "val4" as input and then immediately
 removes it from the stack using "POP". The stack is now empty but
-as a side result we now know the time that this sample was taken.
+as a side effect we now know the time that this sample was taken.
 This time is put on the stack by the "TIME" function.
 
-"TIME,7200,%" takes the modulo of time and 7200 (which is two hours).
+"TIME,7200,%" takes the modulo of time and 7'200 (which is two hours).
 The resulting value on the stack will be a number in the range from
 0 to 7199.
 
@@ -826,7 +830,8 @@ won't do that here.
 Now you can draw the different layers. Start with the background
 that is either unknown (nothing to see) or infinite (the whole
 positive part of the graph gets filled).
-Next you draw the data on top of this background. It will overlay
+
+Next you draw the data on top of this background, it will overlay
 the background. Suppose one of val1..val4 would be unknown, in that
 case you end up with only three bars stacked on top of each other.
 You don't want to see this because the data is only valid when all
@@ -837,7 +842,7 @@ If your data can also have negative values you also need to overwrite
 the other half of your graph. This can be done in a relatively simple
 way: what you need is the "wipeout" variable and place a negative
 sign before it:  "CDEF:wipeout2=wipeout,-1,*"
-    
+
 =head2 Filtering data
 
 You may do some complex data filtering:
@@ -866,10 +871,11 @@ You may do some complex data filtering:
 
 =head1 Out of ideas for now
 
-This document was created from questions asked by either myself or
-by other people on the list. Please let me know if you find errors
-in it or if you have trouble understanding it. If you think there
-should be an addition, mail me: E<lt>alex@ergens.op.het.netE<gt>
+This document was created from questions asked by either myself or by
+other people on the RRDtool mailing list. Please let me know if you
+find errors in it or if you have trouble understanding it. If you
+think there should be an addition, mail me:
+E<lt>alex@ergens.op.het.netE<gt>
 
 Remember: B<No feedback equals no changes!>
 
index 056f27fdcc216b16748cf590a3b64e285820d466..dffcae4ed7bdd8200158b818d1868a4e7c9ea607 100644 (file)
@@ -8,11 +8,4 @@ WARNING: DO NOT EDIT THE POD FILES. THEY ARE AUTO-GENERATED
 
 rrdtool graph - Round Robin Database tool grapher functions
 
-WARNING: This is for version 1.1.x which is B<I<BETA>> software.
-The software may contain serious bugs. Some of the items
-described in here may not yet exist (although this should
-be mentioned) or still be in the alpha stage.  As with every
-other RRDtool release: use at your own risk.  In contrast with
-the stable version of RRDtool, this release may contain bugs
-known to the authors.  It is highly recommended that you subscribe
-to the mailing list.
+Documentation for version 1.2.0
index 13ee0ecd04977d82cc1e60e7043f329ace689b56..b3beac1ded0735012874a4340affb79b1a833e38 100644 (file)
@@ -2,8 +2,6 @@
 
 rpntutorial - Reading RRDtool RPN Expressions by Steve Rader
 
-=for html <div align="right"><a href="rpntutorial.pdf">PDF</a> version.</div>
-
 =head1 DESCRIPTION
 
 This tutorial should help you get to grips with RRDtool RPN expressions
@@ -15,18 +13,18 @@ The LT, LE, GT, GE and EQ RPN logic operators are not as tricky as
 they appear.  These operators act on the two values on the stack
 preceding them (to the left).  Read these two values on the stack
 from left to right inserting the operator in the middle.  If the
-resulting statement is true, the replace the three values from the
+resulting statement is true, then replace the three values from the
 stack with "1".  If the statement if false, replace the three values
 with "0".
 
-For example think about "2,1,GT".  This RPN expression could be
+For example, think about "2,1,GT".  This RPN expression could be
 read as "is two greater than one?"  The answer to that question is
 "true".  So the three values should be replaced with "1".  Thus the
 RPN expression 2,1,GT evaluates to 1.
 
-Now also consider "2,1,LE".  This RPN expression could be read as "is
+Now consider "2,1,LE".  This RPN expression could be read as "is
 two less than or equal to one?".   The natural response is "no"
-and thus the RPN expression 2,1,LE evaluates to 0. 
+and thus the RPN expression 2,1,LE evaluates to 0.
 
 =head1 Reading the IF Operator
 
@@ -58,14 +56,14 @@ GT, GE and EQ operators.
 While compound expressions can look overly complex, they can be
 considered elegantly simple.  To quickly comprehend RPN expressions,
 you must know the the algorithm for evaluating RPN expressions:
-iterate searches from the left to the right looking for an operator,
-when it's found, apply that operator by popping the operator and some
+iterate searches from the left to the right looking for an operator.
+When it's found, apply that operator by popping the operator and some
 number of values (and by definition, not operators) off the stack.
 
 For example, the stack "1,2,3,+,+" gets "2,3,+" evaluated (as "2+3")
-during the first iteration which is replaced by 5.  This results in
+during the first iteration and is replaced by 5.  This results in
 the stack "1,5,+".  Finally, "1,5,+" is evaluated resulting in the
-answer 6.  For convenience sake, it's useful to write this set of
+answer 6.  For convenience, it's useful to write this set of
 operations as:
 
  1) 1,2,3,+,+    eval is 2,3,+ = 5    result is 1,5,+
@@ -78,7 +76,7 @@ with multiple logic operators:
  1) 20,10,GT,10,20,IF  eval is 20,10,GT = 1     result is 1,10,20,IF
 
 read the eval as pop "20 is greater than 10" so push 1
+
  2) 1,10,20,IF         eval is 1,10,20,IF = 10  result is 10
 
 read pop "if 1 then 10 else 20" so push 10.  Only 10 is left so
@@ -93,23 +91,23 @@ multiplication operator:
  4) 0,7000,1024,IF                                      result is 1024
 
 
-Now let's go back to the first example of multiple logic operators
+Now let's go back to the first example of multiple logic operators,
 but replace the value 20 with the variable "input":
 
- 1) input,10,GT,10,input,IF  eval is input,10,GT  result is A
+ 1) input,10,GT,10,input,IF  eval is input,10,GT  ( lets call this A )
 
 Read eval as "if input > 10 then true" and replace "input,10,GT"
-with "A:
-  
+with "A":
+
  2) A,10,input,IF            eval is A,10,input,IF
 
-read "if A then 10 else input".  Now replace A it's verbose
-description and--voila!--you have a easily readable description
+read "if A then 10 else input".  Now replace A with it's verbose
+description againg and--voila!--you have a easily readable description
 of the expression:
 
  if input > 10 then 10 else input
 
-Lastly, let's to back the first most complex example and replace
+Finally, let's go back to the first most complex example and replace
 the value 128 with "input":
 
  1) input,8,*,7000,GT,7000,input,8,*,IF  eval input,8,*     result is A
@@ -141,7 +139,7 @@ traditional notation.  Explain why they have different answers.
 Answer 1:
 
     3*2+1 = 7 and 3*(2+1) = 9.  These expressions have
-    different answers because the altering of the plus and 
+    different answers because the altering of the plus and
     times operators alter the order of their evaluation.
 
 
@@ -155,8 +153,8 @@ by removing the redundant use of "input,8,*" like so:
 
  input,56000,GT,56000,input,IF,8,*
 
-Use tradition notation to show these expressions are not the same.
-Write an expression that's equivalent to the first expression but
+Use traditional notation to show these expressions are not the same.
+Write an expression that's equivalent to the first expression, but
 uses the LE and DIV operators.
 
 Answer 2:
@@ -183,7 +181,7 @@ Answer 3:
 
 Exercise 4:
 
-Explain why it is desirable for the RRDtool developers to implement
+Explain why it was desirable for the RRDtool developers to implement
 RPN notation instead of traditional mathematical notation.
 
 Answer 4:
index 363cc2e1053a3c6ce4e169d8006aff4fe2b05b0e..5ac79973f6d728864867c30dedb3f53289667cfe 100644 (file)
@@ -1,6 +1,6 @@
-=head1 NAME 
+=head1 NAME
 
-rrd-beginners - Beginners guide
+rrd-beginners - RRDtool Beginners' Guide
 
 =head1 SYNOPSIS
 
@@ -10,35 +10,35 @@ Helping new RRDtool users to understand the basics of RRDtool
 
 This manual is an attempt to assist beginners in understanding the concepts
 of RRDtool. It sheds a light on differences between RRDtool and other
-databases. With help of an example, it explains structure of RRDtool
+databases. With help of an example, it explains the structure of RRDtool
 database. This is followed by an overview of the "graph" feature of RRDtool.
-At the end, it has sample scripts that illustrates the
+At the end, it has sample scripts that illustrate the
 usage/wrapping of RRDtool within Shell or Perl scripts.
 
 =head2 What makes RRDtool so special?
 
 RRDtool is GNU licensed software developed by Tobias Oetiker, a system
 manager at the Swiss Federal Institute of Technology. Though it is a
-database, there are distinct differences between RRDtool database and other
+database, there are distinct differences between RRDtool databases and other
 databases as listed below:
 
 =over
 
 =item *
 
-RRDtool stores data; that makes it a back end tool. The RRDtool command set
-allows the creation of graphs; that makes it a front end tool as well. Other
-databases just stores data and can not create graphs.
+RRDtool stores data; that makes it a back-end tool. The RRDtool command set
+allows the creation of graphs; that makes it a front-end tool as well. Other
+databases just store data and can not create graphs.
 
 =item *
 
 In case of linear databases, new data gets appended at the bottom of
-the database table. Thus its size keeps on increasing, whereas size of an RRDtool
-database is determined at creation time. Imagine an RRDtool database as the
-perimeter of a circle. Data is added along the perimeter. When new data
-reaches the starting point, it overwrites existing data. This way, the size of
-an RRDtool database always remains constant. The name "Round Robin" stems from this
-attribute.
+the database table. Thus its size keeps on increasing, whereas the size of
+an RRDtool database is determined at creation time. Imagine an RRDtool
+database as the perimeter of a circle. Data is added along the
+perimeter. When new data reaches the starting point, it overwrites
+existing data. This way, the size of an RRDtool database always
+remains constant. The name "Round Robin" stems from this behavior.
 
 =item *
 
@@ -52,24 +52,25 @@ Other databases get updated when values are supplied. The RRDtool database
 is structured in such a way that it needs data at predefined time
 intervals. If it does not get a new value during the interval, it stores an
 UNKNOWN value for that interval. So, when using the RRDtool database, it is
-imperative to use scripts that runs at regular intervals to ensure a constant
+imperative to use scripts that run at regular intervals to ensure a constant
 data flow to update the RRDtool database.
 
 =back
-  
-RRDtool has a lot to do with time. With every data update, it also needs to
-know the time when that update occurred. Time is always expressed in
-seconds passed since epoch (01-01-1971). RRDtool can be installed on Unix as
-well as Windows. It has command set to carry out various
-operations on RRD database. This command set can be accessed from the command line,
-and from Shell or Perl scripts. The scripts
-act as wrappers for accessing data stored in RRDtool database.
-  
+
+RRDtool is designed to store time series of data. With every data
+update, an associated time stamp is stored. Time is always expressed
+in seconds passed since epoch (01-01-1970). RRDtool can be installed
+on Unix as well as Windows. It comes with a command set to carry out
+various operations on RRD databases. This command set can be accessed
+from the command line, as well as from Shell or Perl scripts. The
+scripts act as wrappers for accessing data stored in RRDtool
+databases.
+
 =head2 Understanding by an example
 
 The structure of an RRD database is different than other linear databases.
 Other databases define tables with columns, and many other parameters. These
-definitions sometime are very complex, especially in large databases.
+definitions sometimes are very complex, especially in large databases.
 RRDtool databases are primarily used for monitoring purposes and
 hence are very simple in structure. The parameters
 that need to be defined are variables that hold values and archives of those
@@ -83,143 +84,152 @@ terminologies related to RRDtool databases.
 The structure of a database and the terminology associated with it can be
 best explained with an example.
 
- rrdtool create target.rrd
-         --start 1023654125
-         --step 300
-         DS:mem:GAUGE:600:0:671744
-         RRA:AVERAGE:0.5:12:24
+ rrdtool create target.rrd \
+         --start 1023654125 \
+         --step 300 \
+         DS:mem:GAUGE:600:0:671744 \
+         RRA:AVERAGE:0.5:12:24 \
          RRA:AVERAGE:0.5:288:31
 
-This example creates a database named F<target.rrd>. Start time (1023654125) is
-specified in total number of seconds since epoch (time in seconds since
-01-01-1970). While updating the database, update time is also specified.
-This update time MUST occur after start time and MUST be in seconds since
-epoch.
+This example creates a database named F<target.rrd>. Start time
+(1'023'654'125) is specified in total number of seconds since epoch
+(time in seconds since 01-01-1970). While updating the database, the
+update time is also specified.  This update time MUST be large (later)
+then start time and MUST be in seconds since epoch.
 
 The step of 300 seconds indicates that database expects new values every
 300 seconds. The wrapper script should be scheduled to run every B<step>
 seconds so that it updates the database every B<step> seconds.
 
 DS (Data Source) is the actual variable which relates to the parameter on
-the device that has to be monitored. Its syntax is
+the device that is monitored. Its syntax is
 
  DS:variable_name:DST:heartbeat:min:max
 
 B<DS> is a key word. C<variable_name> is a name under which the parameter is
-saved in database. There can be as many DSs in a database as needed. After
+saved in the database. There can be as many DSs in a database as needed. After
 every step interval, a new value of DS is supplied to update the database.
-This value is also called as Primary Data Point B<(PDP)>. In our example
+This value is also called Primary Data Point B<(PDP)>. In our example
 mentioned above, a new PDP is generated every 300 seconds.
 
 Note, that if you do NOT supply new datapoints exactly every 300 seconds,
-this is not problem, RRDtool will interpolate the data accordingly.
-
-B<DST> (Data Source Type) defines type of DS. It can be COUNTER, DERIVE,
-ABSOLUTE, GAUGE. A DS declared as COUNTER will save the rate of change of
-the value over a step period. This assumes that the value is always
-increasing (difference between last two values is more than 0). Traffic
-counters on a router is an ideal candidate for using COUNTER as DST. DERIVE
-is same as COUNTER but it allows negative values as well. If you want to see
-the rate of I<change> in free diskspace on your server, then you might want to
-use the DERIVE data type. ABSOLUTE also saves the rate of change but it assumes
-that previous value is set to 0. The difference between current and previous
-value is always equal to the current value. So, it stores the current value divided
-by step interval (300 seconds in our example). GAUGE does not save the rate of
-change. It saves the actual value itself. There are no
-divisions/calculations. Memory consumption in a server is an ideal
-example of gauge. Difference among different types DSTs can be explained
-better with following example:
+this is not a problem, RRDtool will interpolate the data accordingly.
+
+B<DST> (Data Source Type) defines the type of the DS. It can be
+COUNTER, DERIVE, ABSOLUTE, GAUGE. A DS declared as COUNTER will save
+the rate of change of the value over a step period. This assumes that
+the value is always increasing (the difference between the current and
+the previous value is greater than 0). Traffic counters on a router
+are an ideal candidate for using COUNTER as DST. DERIVE is the same as
+COUNTER, but it allows negative values as well. If you want to see the
+rate of I<change> in free diskspace on your server, then you might
+want to use the DERIVE data type. ABSOLUTE also saves the rate of
+change, but it assumes that the previous value is set to 0. The
+difference between the current and the previous value is always equal
+to the current value. Thus it just stores the current value divided by
+the step interval (300 seconds in our example). GAUGE does not save
+the rate of change. It saves the actual value itself. There are no
+divisions or calculations. Memory consumption in a server is a typical
+example of gauge. The difference between the different types DSTs can be
+explained better with the following example:
 
  Values       = 300, 600, 900, 1200
  Step         = 300 seconds
- COUNTER DS   =    1,  1,   1,    1 
+ COUNTER DS   =    1,  1,   1,    1
  DERIVE DS    =    1,  1,   1,    1
- ABSOLUTE DS  =    1,  2,   3,    4 
+ ABSOLUTE DS  =    1,  2,   3,    4
  GAUGE DS     = 300, 600, 900, 1200
 
 The next parameter is B<heartbeat>. In our example, heartbeat is 600
-seconds. If database does not get a new PDP within 300
-seconds, it will wait for another 300 seconds (total 600 seconds).
-If it doesn't receive any PDP with in 600 seconds, it will save an UNKNOWN value
-into database. This UNKNOWN value is a special feature of RRDtool - it is
-much better than to assume a missing value was 0 (zero).
-For example, the traffic flow counter on a router
-keeps on increasing. Lets say, a value is missed for an interval and 0 is stored
-instead of UNKNOWN. Now when next value becomes available, it will calculate
-difference between current value and previous value (0) which is not
-correct. So, inserting value UNKNOWN makes much more sense here.
-
-The next two parameters are the minimum and maximum value respectively. If variable
-to be stored has predictable maximum and minimum value, this should be
-specified here. Any update value falling out of this range will be saved as
-UNKNOWN.
-
-The next line declares a round robin archive (RRA). The syntax for declaring an RRA is
+seconds. If the database does not get a new PDP within 300 seconds, it
+will wait for another 300 seconds (total 600 seconds).  If it doesn't
+receive any PDP within 600 seconds, it will save an UNKNOWN value into
+the database. This UNKNOWN value is a special feature of RRDtool - it
+is much better than to assume a missing value was 0 (zero) or any
+other number which might also be a valid data value.  For example, the
+traffic flow counter on a router keeps increasing. Lets say, a value
+is missed for an interval and 0 is stored instead of UNKNOWN. Now when
+the next value becomes available, it will calculate the difference
+between the current value and the previous value (0) which is not
+correct. So, inserting the value UNKNOWN makes much more sense here.
+
+The next two parameters are the minimum and maximum value,
+respectively. If the variable to be stored has predictable maximum and
+minimum values, this should be specified here. Any update value
+falling out of this range will be stored as UNKNOWN.
+
+The next line declares a round robin archive (RRA). The syntax for
+declaring an RRA is
 
  RRA:CF:xff:step:rows
 
-RRA is the keyword to declare RRAs. The consolidation function (CF) can be
-AVERAGE, MINIMUM, MAXIMUM, and LAST. The concept of the consolidated data point (CDP)
-comes into the picture here. A CDP is CFed (averaged, maximum/minimum value or
-last value) from I<step> number of PDPs. This RRA will hold I<rows> CDPs.
-
-Lets have a look at the example above. For the first RRA, 12 (steps) PDPs
-(DS variables) are AVERAGEed (CF) to form one CDP. 24 (rows) of theses CDPs
-are archived. Each PDP occurs at 300 seconds. 12 PDPs represent 12 times 300
-seconds which is 1 hour. It means 1 CDP (which is equal to 12 PDPs)
-represents data worth 1 hour. 24 such CDPs represent 1 day (1 hour times 24
-CDPs). It means, this RRA is an archive for one day. After 24 CDPs, CDP
-number 25 will replace the 1st CDP. Second RRA saves 31 CDPs; each CPD
-represents an AVERAGE value for a day (288 PDPs, each covering 300 seconds =
-24 hours). Therefore this RRA is an archive for one month. A single database
-can have many RRAs. If there are multiple DSs, each individual RRA will save
-data for all the DSs in the database. For example, if a database has 3 DSs;
-and daily, weekly, monthly, and yearly RRAs are declared, then each RRA will
-hold data from all 3 data sources.
+RRA is the keyword to declare RRAs. The consolidation function (CF)
+can be AVERAGE, MINIMUM, MAXIMUM, and LAST. The concept of the
+consolidated data point (CDP) comes into the picture here. A CDP is
+CFed (averaged, maximum/minimum value or last value) from I<step>
+number of PDPs. This RRA will hold I<rows> CDPs.
+
+Lets have a look at the example above. For the first RRA, 12 (steps)
+PDPs (DS variables) are AVERAGEed (CF) to form one CDP. 24 (rows) of
+theses CDPs are archived. Each PDP occurs at 300 seconds. 12 PDPs
+represent 12 times 300 seconds which is 1 hour. It means 1 CDP (which
+is equal to 12 PDPs) represents data worth 1 hour. 24 such CDPs
+represent 1 day (1 hour times 24 CDPs). This means, this RRA is an
+archive for one day. After 24 CDPs, CDP number 25 will replace the 1st
+CDP. The second RRA saves 31 CDPs; each CPD represents an AVERAGE
+value for a day (288 PDPs, each covering 300 seconds = 24
+hours). Therefore this RRA is an archive for one month. A single
+database can have many RRAs. If there are multiple DSs, each
+individual RRA will save data for all the DSs in the database. For
+example, if a database has 3 DSs and daily, weekly, monthly, and
+yearly RRAs are declared, then each RRA will hold data from all 3 data
+sources.
 
 =head2 Graphical Magic
 
-Another important feature of RRDtool is its ability to create graphs. The
-"graph" command uses "fetch" command internally to retrieve values from the
-database. With the retrieved values, it draws graphs as defined by the
-parameters supplied on the command line. A single graph can show different
-DS (Data Sources0) from a database. It is also possible to show the
-values from more than one databases into a single graph. Often, it is
-necessary to perform some math on the values retrieved from database, before
-plotting them. For example, in SNMP replies, memory consumption values are
-usually specified in KBytes and traffic flow on interfaces is specified in
-Bytes. Graphs for these values will be more senseful if values are
-represented in MBytes and mbps. the RRDtool graph command allows to define
-such conversions. Apart from mathematical calculations, it is also possible
-to perform logical operations such as greater than, less than, and if then
-else. If a database contains more than one RRA archive, then a question may
-arise - how does RRDtool decide which RRA archive to use for retrieving the
-values? RRDtool takes looks at several things when making its choice. First
-it makes sure that the RRA covers as much of the graphing time frame as
-possible. Second it looks at the resolution of the RRA compared to the
-resolution of the graph. It tries to find one which has the same or better
-resolution. With the "-r" option you can force RRDtool to assume a different
-resolution than the one calculated from the pixel width of the graph.
-
-Values of different variables can be presented in 5 different shapes in a
-graph - AREA, LINE1, LINE2, LINE3, and STACK. AREA is represented by a solid
-colored area with values as the boundary of this area. LINE1/2/3 (increasing
-width) are just plain lines representing the values. STACK is also an area
-but it is "stack"ed on AREA or LINE1/2/3. Another important thing to note,
-is that variables are plotted in the order they are defined in graph
-command. So, care must be taken to define STACK only after defining
-AREA/LINE. It is also possible to put formatted comments within the graph.
-Detailed instructions be found under graph manual.
+Another important feature of RRDtool is its ability to create
+graphs. The "graph" command uses the "fetch" command internally to
+retrieve values from the database. With the retrieved values it draws
+graphs as defined by the parameters supplied on the command line. A
+single graph can show different DS (Data Sources) from a database. It
+is also possible to show the values from more than one database in a
+single graph. Often, it is necessary to perform some math on the
+values retrieved from the database before plotting them. For example,
+in SNMP replies, memory consumption values are usually specified in
+KBytes and traffic flow on interfaces is specified in Bytes. Graphs
+for these values will be more meaningful if values are represented in
+MBytes and mbps. The RRDtool graph command allows to define such
+conversions. Apart from mathematical calculations, it is also possible
+to perform logical operations such as greater than, less than, and
+if/then/else. If a database contains more than one RRA archive, then a
+question may arise - how does RRDtool decide which RRA archive to use
+for retrieving the values? RRDtool looks at several things when making
+its choice. First it makes sure that the RRA covers as much of the
+graphing time frame as possible. Second it looks at the resolution of
+the RRA compared to the resolution of the graph. It tries to find one
+which has the same or higher better resolution. With the "-r" option
+you can force RRDtool to assume a different resolution than the one
+calculated from the pixel width of the graph.
+
+Values of different variables can be presented in 5 different shapes
+in a graph - AREA, LINE1, LINE2, LINE3, and STACK. AREA is represented
+by a solid colored area with values as the boundary of this
+area. LINE1/2/3 (increasing width) are just plain lines representing
+the values. STACK is also an area but it is "stack"ed on top AREA or
+LINE1/2/3. Another important thing to note is that variables are
+plotted in the order they are defined in the graph command. Therefore
+care must be taken to define STACK only after defining AREA/LINE. It
+is also possible to put formatted comments within the graph.  Detailed
+instructions can be found in the graph manual.
 
 =head2 Wrapping RRDtool within Shell/Perl script
 
-After understanding RRDtool, it is now a time to actually use RRDtool in
-scripts. Tasks involved in network management are data collection, data
-storage, and data retrieval. In the following example,
-the previously created target.rrd database is used. Data collection and data
-storage is done using Shell scrip. Data retrieval
-and report generation is done using Perl script. These
-scripts are as shown below:
+After understanding RRDtool it is now a time to actually use RRDtool
+in scripts. Tasks involved in network management are data collection,
+data storage, and data retrieval. In the following example, the
+previously created target.rrd database is used. Data collection and
+data storage is done using Shell scripts. Data retrieval and report
+generation is done using Perl scripts. These scripts are shown below:
 
 =head3 Shell script (collects data, updates database)
 
@@ -241,21 +251,21 @@ scripts are as shown below:
 =head3 Perl script (retrieves data from database and generates graphs and statistics)
 
  #!/usr/bin/perl -w
- #This script fetch data from target.rrd, creates graph of memory consumption
on target (Dual P3 Processor 1 GHz, 656 MB RAM)
+ # This script fetches data from target.rrd, creates a graph of memory
# consumption on the target (Dual P3 Processor 1 GHz, 656 MB RAM)
 
- #calling RRD perl module
+ # call the RRD perl module
  use lib qw( /usr/local/rrdtool-1.0.41/lib/perl ../lib/perl );
  use RRDs;
- my $cur_time = time();                # setting current time
- my $end_time = $cur_time - 86400;     # setting end time to 24 hours behind current time
- my $start_time = $end_time - 2592000; # setting start time to 30 days from end time
+ my $cur_time = time();                # set current time
+ my $end_time = $cur_time - 86400;     # set end time to 24 hours ago
+ my $start_time = $end_time - 2592000; # set start 30 days in the past
 
- #fetching average values from RRD database between start and end time
- my ($start,$step,$ds_names,$data) = 
-     RRDs::fetch("target.rrd", "AVERAGE", 
+ # fetch average values from the RRD database between start and end time
+ my ($start,$step,$ds_names,$data) =
+     RRDs::fetch("target.rrd", "AVERAGE",
                  "-r", "600", "-s", "$start_time", "-e", "$end_time");
- #saving fetched values in 2-dimensional array
+ # save fetched values in a 2-dimensional array
  my $rows = 0;
  my $columns = 0;
  my $time_variable = $start;
@@ -269,19 +279,19 @@ scripts are as shown below:
  }
  my $tot_time = 0;
  my $count = 0;
- #saving values from 2-dimensional into 1-dimensional array
+ # save the values from the 2-dimensional into a 1-dimensional array
  for $i ( 0 .. $#vals ) {
      $tot_mem[$count] = $vals[$i][1];
      $count++;
  }
  my $tot_mem_sum = 0;
- #calculating total of all values
+ # calculate the total of all values
  for $i ( 0 .. ($count-1) ) {
      $tot_mem_sum = $tot_mem_sum + $tot_mem[$i];
  }
- #calculating average of array
+ # calculate the average of the array
  my $tot_mem_ave = $tot_mem_sum/($count);
- #creating graph
+ # create the graph
  RRDs::graph ("/images/mem_$count.png",   \
              "--title= Memory Usage",    \
              "--vertical-label=Memory Consumption (MB)", \
@@ -296,16 +306,16 @@ scripts are as shown below:
              "--rigid",                  \
              "--base=1024",              \
              "DEF:tot_mem=target.rrd:mem:AVERAGE", \
-             "CDEF:correct_tot_mem=tot_mem,0,671744,LIMIT,UN,0,tot_mem,IF,1024,/",\
+             "CDEF:tot_mem_cor=tot_mem,0,671744,LIMIT,UN,0,tot_mem,IF,1024,/",\
              "CDEF:machine_mem=tot_mem,656,+,tot_mem,-",\
              "COMMENT:Memory Consumption between $start_time",\
              "COMMENT:    and $end_time                     ",\
              "HRULE:656#000000:Maximum Available Memory - 656 MB",\
              "AREA:machine_mem#CCFFFF:Memory Unused",   \
-             "AREA:correct_tot_mem#6699CC:Total memory consumed in MB");
+             "AREA:tot_mem_cor#6699CC:Total memory consumed in MB");
  my $err=RRDs::error;
  if ($err) {print "problem generating the graph: $err\n";}
- #printing the output
+ # print the output
  print "Average memory consumption is ";
  printf "%5.2f",$tot_mem_ave/1024;
  print " MB. Graphical representation can be found at /images/mem_$count.png.";
diff --git a/doc/rrdbuild.pod b/doc/rrdbuild.pod
new file mode 100644 (file)
index 0000000..7a24a82
--- /dev/null
@@ -0,0 +1,205 @@
+=head1 NAME
+
+rrdbuild - Instructions for building RRDtool
+
+=head1 DESCRIPTION
+
+=head2 Overview
+
+If you downloaded the source of rrdtool you have to compile it. This
+document will give some information on how this is done.
+
+RRDtool relies on services of thrid part libraries. Some of these libraries
+may already be installed on your system. You have to compile copies of the other
+ones before you can build RRDtool.
+
+This document will tell you about all the necessary steps to get going.
+
+=head2 Building
+
+Before you start to build RRDtool, you have to decide two things:
+
+=over
+
+=item 1.
+
+In which directory you want to build the software.
+
+=item 2.
+
+Where you want to install the software.
+
+=back
+
+Once you have decided. Save the two locations into environment variables.
+Depending on the shell you are using, you can do either (bash,zsh):
+
+ BUILD_DIR=/tmp/rrdbuild
+ INSTALL_DIR=/usr/local/rrdtool-1.2.23
+
+Or if you run tcsh:
+
+ set BUILD_DIR=/tmp/rrdbuild
+ set INSTALL_DIR=/usr/local/rrdtool-1.2.23
+
+If your F</tmp> is mounted with the option noexec (RHEL seems todo that) you have to choose
+a different directory!
+
+Now make sure the BUILD_DIR exists and go there:
+
+ mkdir -p $BUILD_DIR
+ cd $BUILD_DIR
+
+Lets first assume you already have all the necessary libraries
+pre-installed. Note that these instructions assume that your copies of
+B<tar> and B<make> are actually B<GNU tar> and B<GNU make> respectively. It
+could be that they are installed as B<gtar> and B<gmake> on your system.
+
+ wget http://oss.oetiker.ch/rrdtool/pub/rrdtool-1.2.23.tar.gz
+ tar zxf rrdtool-1.2.23.tar.gz
+ cd rrdtool-1.2.23
+ ./configure --prefix=$INSTALL_DIR && make && make install
+
+Ok, this was very optimistic. This try will probably have ended with
+B<configure> complaining about several missing libraries. If you are on a
+Linux or *bsd system you may want to just install the missing bits from your
+software repository. When you do that, make sure you also get the B<-dev>
+package for each library you install. Once you have the missing bits on
+board, just re-run the last line of the instructions above.
+
+But again this may have been too optimistic, and you actually have to
+compile your own copies of the required libraries.
+
+=head3 Build Tipps for AIX
+
+If you are woking with AIX, you may find the the B<--disable-shared> option
+will cause things to break for you. In that case you may have to install the
+shared libraries into the rrdtool PREFIX and work with B<--disable-static>
+instead.
+
+Another hint to get rrdtool working on AIX is to use the IBM XL C Compiler:
+
+ export CC=/usr/vac/bin/cc
+ export PERLCC=$CC
+
+(Better instructions for AIX welcome!)
+
+=head2 Building Libraries
+
+In order to build the libraries you need a compiler on your system.
+Unfortunately compilers are not all alike. This has an effect on the CFLAGS
+you want to set. The examples below are for the popular GCC compiler suite.
+If you have an other compile you have to use the following settings:
+
+=over
+
+=item Sun Forte
+
+ CFLAGS="-xO3 -kPIC"
+
+=back
+
+=over 
+
+=item Building zlib
+
+ cd $BUILD_DIR
+ wget http://oss.oetiker.ch/rrdtool/pub/libs/zlib-1.2.3.tar.gz
+ tar  zxf zlib-1.2.3.tar.gz
+ cd zlib-1.2.3
+ env CFLAGS="-O3 -fPIC" ./configure --prefix=$BUILD_DIR/lb
+ make
+ make install
+
+=item Building libpng
+
+Libpng itself requires zlib to build, so we need to help a bit. If you
+already have a copy of zlib on your system (which is very likley) you can
+drop the settings of LDFLAGS and CPPFLAGS. Note that the backslash (\) at
+the end of line 4 means that line 4 and line 5 are on one line.
+
+ cd $BUILD_DIR
+ wget http://oss.oetiker.ch/rrdtool/pub/libs/libpng-1.2.10.tar.gz
+ tar zxvf libpng-1.2.10.tar.gz
+ cd libpng-1.2.10
+ env CPPFLAGS="-I$BUILD_DIR/lb/include" LDFLAGS="-L$BUILD_DIR/lb/lib" CFLAGS="-O3 -fPIC" \
+     ./configure --disable-shared --prefix=$BUILD_DIR/lb
+ make
+ make install
+
+=item Building freetype
+
+ cd $BUILD_DIR
+ wget http://oss.oetiker.ch/rrdtool/pub/libs/freetype-2.1.10.tar.bz2
+ tar jxvf freetype-2.1.10.tar.bz2
+ cd freetype-2.1.10
+ env CPPFLAGS="-I$BUILD_DIR/lb/include" LDFLAGS="-L$BUILD_DIR/lb/lib" CFLAGS="-O3 -fPIC" \
+     ./configure --disable-shared --prefix=$BUILD_DIR/lb
+ make
+ make install
+
+If you run into problems building freetype on Solaris, you may want to try to
+add the following at the end of the configure line:
+
+ GNUMAKE=gmake EGREP=egrep
+
+=item Building libart_lgpl
+
+ cd $BUILD_DIR
+ wget http://oss.oetiker.ch/rrdtool/pub/libs/libart_lgpl-2.3.17.tar.gz
+ tar zxvf libart_lgpl-2.3.17.tar.gz
+ cd libart_lgpl-2.3.17
+ env CFLAGS="-O3 -fPIC" ./configure --disable-shared --prefix=$BUILD_DIR/lb
+ make
+ make install
+
+=back
+
+Now all the dependent libraries are built and you can try again. Since these
+are static libraries, you may have to use F<ranlib> to make them accessible.
+Especially BSD systems like Mac OS X may require this, Linux and Solaris
+will do just fine without since their F<ar> command does ranlibs job as well.
+
+ ranlib $BUILD_DIR/lb/lib/*.a
+
+This time you tell configure where it should be looking for libraries and
+include files. This is done via environment variables. Depending on the
+shell you are running, the syntax for setting environment variables is
+different. Under csh/tcsh you use:
+
+ set IR=-I$BUILD_DIR/lb/include
+ setenv CPPFLAGS "$IR $IR/libart-2.0 $IR/freetype2 $IR/libpng"
+ setenv LDFLAGS  -L$BUILD_DIR/lb/lib
+ setenv CFLAGS -O3
+
+If you are running bash/sh/ash/ksh/zsh use this:
+
+ IR=-I$BUILD_DIR/lb/include
+ CPPFLAGS="$IR $IR/libart-2.0 $IR/freetype2 $IR/libpng"
+ LDFLAGS="-L$BUILD_DIR/lb/lib"
+ CFLAGS=-O3
+ export CPPFLAGS LDFLAGS CFLAGS
+
+And finally try building again. We disable the python and tcl bindings
+because it seems that a fair number of people have ill configured python and
+tcl setups that would prevent rrdtool from building if they are included in
+their current state.
+
+ cd $BUILD_DIR/rrdtool-1.2.23
+ ./configure --prefix=$INSTALL_DIR --disable-python --disable-tcl
+ make clean
+ make
+ make install
+
+SOLARIS HINT: if you want to build  the perl module for the native perl (the
+one shipping with solaris) you will need the sun forte compiler
+installed on your box or you have to hand-tune bindings/perl-shared/Makefile
+while building!
+
+Now go to I<$INSTALL_DIR>B</share/rrdtool/examples/> and run them to see if your
+build has been successful.
+
+=head1 AUTHOR
+
+Tobias Oetiker E<lt>tobi@oetiker.chE<gt>
+
index 763ab230bb8168eea19af9c1bc0bce78b6c67bca..4c81e018d41a244f2c54e26e39b32adc48e1967e 100644 (file)
@@ -1,13 +1,10 @@
 =head1 NAME
 
-rrdcgi - create web pages containing RRD graphs based on templates
-
-=for html <div align="right"><a href="rrdcgi.pdf">PDF</a> version.</div>
+rrdcgi - Create web pages containing RRD graphs based on templates
 
 =head1 SYNOPSIS
 
-#!/path/to/B<rrdcgi> 
-S<[B<--filter>]>
+C<#!/path/to/>B<rrdcgi> S<[B<--filter>]>
 
 =head1 DESCRIPTION
 
@@ -17,16 +14,15 @@ E<lt>RRD:: tags. B<rrdcgi> will interpret and act according to these tags.
 In the end it will printout a web page including the necessary CGI headers.
 
 B<rrdcgi> parses the contents of the template in 3 steps. In each step it looks
-only for a subset of tags. This allows to nest tags. 
+only for a subset of tags. This allows nesting of tags.
 
-The argument parser uses the same semantics as you are used from your shell.
+The argument parser uses the same semantics as you are used from your C-shell.
 
 =over 8
 
-
 =item B<--filter>
 
-Assume that rrdcgi is being run as a filter and not as a cgi.
+Assume that rrdcgi is run as a filter and not as a cgi.
 
 =back
 
@@ -42,13 +38,13 @@ Inserts the CGI variable of the given name.
 
 Inserts the CGI variable of the given name but quotes it, ready for
 use as an argument in another RRD:: tag. So even when there are spaces in the
-value of the CGI variable it will still be considered as one argument.
+value of the CGI variable it will still be considered to be one argument.
 
 =item RRD::CV::PATH I<name>
 
 Inserts the CGI variable of the given name, quotes it and makes sure
-the it starts neither with a '/' nor contains '..'. This is to make
-sure that no problematic pathnames can be introduced through the 
+it starts neither with a '/' nor contains '..'. This is to make
+sure that no problematic pathnames can be introduced through the
 CGI interface.
 
 =item RRD::GETENV I<variable>
@@ -58,18 +54,18 @@ Get the value of an environment variable.
  <RRD::GETENV REMOTE_USER>
 
 might give you the name of the remote user given you are using
-some sort of access control on the directory
+some sort of access control on the directory.
 
 
 =item RRD::GOODFOR I<seconds>
 
 Specify the number of seconds this page should remain valid. This will prompt
 the rrdcgi to output a Last-Modified, an Expire and if the number of
-seconds is I<negative> a Refresh headers.
+seconds is I<negative> a Refresh header.
 
 =item RRD::INCLUDE I<filename>
 
-Include the contents of the given file into the page returned from the cgi
+Include the contents of the specified file into the page returned from the cgi.
 
 =item RRD::SETENV I<variable> I<value>
 
@@ -83,11 +79,11 @@ values permitted to TZ depend on your OS.
 
 =item RRD::SETVAR I<variable> I<value>
 
-Analog to SETENV but for local variables
+Analog to SETENV but for local variables.
 
-=item RRD::GETVAR I<variable> 
+=item RRD::GETVAR I<variable>
 
-Analog to GETENV but for local variables
+Analog to GETENV but for local variables.
 
 =item RRD::TIME::LAST I<rrd-file> I<strftime-format>
 
@@ -99,8 +95,9 @@ time is I<strftime>-formatted with the string specified in the second argument.
 This gets replaced by the current time of day. The time is
 I<strftime>-formatted with the string specified in the argument.
 
-Note that if you return : from your strftime format you may have to escape
-them using \ if the time is to be used as an argument to a GRAPH command. 
+Note that if you return : (colons) from your strftime format you may
+have to escape them using \ if the time is to be used as an argument
+to a GRAPH command.
 
 =item RRD::TIME::STRFTIME I<START|END> I<start-spec> I<end-spec> I<strftime-format>
 
@@ -111,13 +108,14 @@ must be supplied as either could be relative to the other.  This is intended
 to allow pretty titles on graphs with times that are easier for non RRDtool
 folks to figure out than "-2weeks".
 
-Note that if you return : from your strftime format you may have to escape
-them using \ if the time is to be used as an argument to a GRAPH command.
+Note that again, if you return : (colon) from your strftime format,
+you may have to escape them using \ if the time is to be used as an
+argument to a GRAPH command.
 
 =item RRD::GRAPH I<rrdgraph arguments>
 
-This tag creates the RRD graph defined in its argument and then gets
-replaced by an appropriate E<lt>IMG<gt> tag referring to the graph.
+This tag creates the RRD graph defined by its argument and then is
+replaced by an appropriate E<lt>IMG ... E<gt> tag referring to the graph.
 The B<--lazy> option in RRD graph can be used to make sure that graphs
 are only regenerated when they are out of date. The arguments
 to the B<RRD::GRAPH> tag work as described in the B<rrdgraph> manual page.
@@ -140,6 +138,12 @@ If the preceding  B<RRD::GRAPH> tag contained and B<PRINT> arguments,
 then you can access their output with this tag. The I<number> argument refers to the
 number of the B<PRINT> argument. This first B<PRINT> has I<number> 0.
 
+=item RRD::INTERNAL <var>
+
+This tag gets replaced by an internal var. Currently these vars are known:
+VERSION, COMPILETIME.
+These vars represent the compiled-in values. 
+
 =back
 
 =head1 EXAMPLE 1
@@ -162,9 +166,9 @@ The example below creates a web pages with a single RRD graph.
 
 =head1 EXAMPLE 2
 
-This script is slightly more elaborate, it allows you to run it from 
+This script is slightly more elaborate, it allows you to run it from
 a form which sets RRD_NAME. RRD_NAME is then used to select which RRD
-you want to use a source for your graph.
+you want to use as source for your graph.
 
  #!/usr/local/bin/rrdcgi
  <HTML>
@@ -177,7 +181,7 @@ you want to use a source for your graph.
        <INPUT TYPE=SUBMIT></FORM>
  <H2>Graph</H2>
  <P>
- <RRD::GRAPH <RRD::CV::PATH RRD_NAME>.png --lazy 
+ <RRD::GRAPH <RRD::CV::PATH RRD_NAME>.png --lazy
           --title "Temperatures for "<RRD::CV::QUOTE RRD_NAME>
           DEF:cel=<RRD::CV::PATH RRD_NAME>.rrd:exhaust:AVERAGE
           LINE2:cel#00a000:"D. Celsius">
@@ -213,7 +217,7 @@ webserver/browser
 
 =head1 AUTHOR
 
-Tobias Oetiker E<lt>oetiker@ee.ethz.chE<gt>
+Tobias Oetiker E<lt>tobi@oetiker.chE<gt>
 
 
 
index 3b7fb685772c6baaa743972d96697f2ea1737403..27ef702afd5097ca94e08e13c2b49cb01c3d0559 100644 (file)
@@ -1,23 +1,20 @@
 =head1 NAME
 
-rrdtool create - Set up a new Round Robin Database
-
-=for html <div align="right"><a href="rrdcreate.pdf">PDF</a> version.</div>
+rrdcreate - Set up a new Round Robin Database
 
 =head1 SYNOPSIS
 
-B<rrdtool> B<create> I<filename> 
-S<[B<--start>|B<-b> I<start time>]> 
-S<[B<--step>|B<-s> I<step>]> 
+B<rrdtool> B<create> I<filename>
+S<[B<--start>|B<-b> I<start time>]>
+S<[B<--step>|B<-s> I<step>]>
 S<[B<DS:>I<ds-name>B<:>I<DST>B<:>I<dst arguments>]>
 S<[B<RRA:>I<CF>B<:>I<cf arguments>]>
 
 =head1 DESCRIPTION
 
-The create function of the RRDtool lets you set up new
-Round Robin Database (B<RRD>) files. 
-The file is created at its final, full size and filled
-with I<*UNKNOWN*> data.
+The create function of RRDtool lets you set up new Round Robin
+Database (B<RRD>) files.  The file is created at its final, full size
+and filled with I<*UNKNOWN*> data.
 
 =over 8
 
@@ -34,7 +31,7 @@ value should be added to the B<RRD>. B<RRDtool> will not accept
 any data timed before or at the time specified.
 
 See also AT-STYLE TIME SPECIFICATION section in the
-I<rrdfetch> documentation for more ways to specify time.
+I<rrdfetch> documentation for other ways to specify time.
 
 =item B<--step>|B<-s> I<step> (default: 300 seconds)
 
@@ -43,17 +40,17 @@ into the B<RRD>.
 
 =item B<DS:>I<ds-name>B<:>I<DST>B<:>I<dst arguments>
 
-A single B<RRD> can accept input from several data sources (B<DS>).
-(e.g. Incoming and Outgoing traffic on a specific communication
-line). With the B<DS> configuration option you must define some basic
-properties of each data source you want to use to feed the B<RRD>.
+A single B<RRD> can accept input from several data sources (B<DS>),
+for example incoming and outgoing traffic on a specific communication
+line. With the B<DS> configuration option you must define some basic
+properties of each data source you want to store in the B<RRD>.
 
 I<ds-name> is the name you will use to reference this particular data
 source from an B<RRD>. A I<ds-name> must be 1 to 19 characters long in
 the characters [a-zA-Z0-9_].
 
 I<DST> defines the Data Source Type. The remaining arguments of a
-data source entry depend upon the data source type. For GAUGE, COUNTER,
+data source entry depend on the data source type. For GAUGE, COUNTER,
 DERIVE, and ABSOLUTE the format for a data source entry is:
 
 B<DS:>I<ds-name>B<:>I<GAUGE | COUNTER | DERIVE | ABSOLUTE>B<:>I<heartbeat>B<:>I<min>B<:>I<max>
@@ -62,24 +59,26 @@ For COMPUTE data sources, the format is:
 
 B<DS:>I<ds-name>B<:>I<COMPUTE>B<:>I<rpn-expression>
 
-To decide on a data source type, review the definitions that follow. 
-Consult the section on "HOW TO MEASURE" for further insight.
+In order to decide which data source type to use, review the
+definitions that follow. Also consult the section on "HOW TO MEASURE"
+for further insight.
 
 =over 4
 
-=item B<GAUGE> 
+=item B<GAUGE>
 
-is for things like temperatures or number of people in a
-room or value of a RedHat share.
+is for things like temperatures or number of people in a room or the
+value of a RedHat share.
 
 =item B<COUNTER>
 
-is for continuous incrementing counters like the
-ifInOctets counter in a router. The B<COUNTER> data source assumes that
-the counter never decreases, except when a counter overflows.  The update
-function takes the overflow into account.  The counter is stored as a
-per-second rate. When the counter overflows, RRDtool checks if the overflow happened at
-the 32bit or 64bit border and acts accordingly by adding an appropriate value to the result.
+is for continuous incrementing counters like the ifInOctets counter in
+a router. The B<COUNTER> data source assumes that the counter never
+decreases, except when a counter overflows.  The update function takes
+the overflow into account.  The counter is stored as a per-second
+rate. When the counter overflows, RRDtool checks if the overflow
+happened at the 32bit or 64bit border and acts accordingly by adding
+an appropriate value to the result.
 
 =item B<DERIVE>
 
@@ -113,72 +112,77 @@ wrap.
 
 =back
 
-=item B<ABSOLUTE> 
+=item B<ABSOLUTE>
 
 is for counters which get reset upon reading. This is used for fast counters
 which tend to overflow. So instead of reading them normally you reset them
-after every read to make sure you have a maximal time available before the
+after every read to make sure you have a maximum time available before the
 next overflow. Another usage is for things you count like number of messages
 since the last update.
 
 =item B<COMPUTE>
 
-is for storing the result of a formula applied to other data sources in
-the B<RRD>. This data source is not supplied a value on update, but rather
-its Primary Data Points (PDPs) are computed from the PDPs of the data sources
-according to the rpn-expression that defines the formula. Consolidation 
-functions are then applied normally to the PDPs of the COMPUTE data source
-(that is the rpn-expression is only applied to generate PDPs). In database
-software, these are referred to as "virtual" or "computed" columns.
+is for storing the result of a formula applied to other data sources
+in the B<RRD>. This data source is not supplied a value on update, but
+rather its Primary Data Points (PDPs) are computed from the PDPs of
+the data sources according to the rpn-expression that defines the
+formula. Consolidation functions are then applied normally to the PDPs
+of the COMPUTE data source (that is the rpn-expression is only applied
+to generate PDPs). In database software, such data sets are referred
+to as "virtual" or "computed" columns.
 
 =back
 
 I<heartbeat> defines the maximum number of seconds that may pass
-between two updates of this data source before the value of the 
+between two updates of this data source before the value of the
 data source is assumed to be I<*UNKNOWN*>.
 
-I<min> and I<max> are optional entries defining the expected range of
-the data supplied by this data source. If I<min> and/or I<max> are
-defined, any value outside the defined range will be regarded as
-I<*UNKNOWN*>. If you do not know or care about min and max, set them
-to U for unknown. Note that min and max always refer to the processed values
-of the DS. For a traffic-B<COUNTER> type DS this would be the max and min
-data-rate expected from the device.
+I<min> and I<max> define the expected range values for data supplied by a
+data source. If I<min> and/or I<max> any value outside the defined range
+will be regarded as I<*UNKNOWN*>. If you do not know or care about min and
+max, set them to U for unknown. Note that min and max always refer to the
+processed values of the DS. For a traffic-B<COUNTER> type DS this would be
+the maximum and minimum data-rate expected from the device.
 
 I<If information on minimal/maximal expected values is available,
 always set the min and/or max properties. This will help RRDtool in
 doing a simple sanity check on the data supplied when running update.>
 
-I<rpn-expression> defines the formula used to compute the PDPs of a COMPUTE
-data source from other data sources in the same <RRD>. It is similar to defining
-a B<CDEF> argument for the graph command. Please refer to that manual page
-for a list and description of RPN operations supported. For
-COMPUTE data sources, the following RPN operations are not supported: COUNT, PREV,
-TIME, and LTIME. In addition, in defining the RPN expression, the COMPUTE
-data source may only refer to the names of data source listed previously
-in the create command. This is similar to the restriction that B<CDEF>s must
-refer only to B<DEF>s and B<CDEF>s previously defined in the same graph command.
+I<rpn-expression> defines the formula used to compute the PDPs of a
+COMPUTE data source from other data sources in the same <RRD>. It is
+similar to defining a B<CDEF> argument for the graph command. Please
+refer to that manual page for a list and description of RPN operations
+supported. For COMPUTE data sources, the following RPN operations are
+not supported: COUNT, PREV, TIME, and LTIME. In addition, in defining
+the RPN expression, the COMPUTE data source may only refer to the
+names of data source listed previously in the create command. This is
+similar to the restriction that B<CDEF>s must refer only to B<DEF>s
+and B<CDEF>s previously defined in the same graph command.
 
 =item B<RRA:>I<CF>B<:>I<cf arguments>
 
 
 The purpose of an B<RRD> is to store data in the round robin archives
-(B<RRA>). An archive consists of a number of data values or statistics for 
+(B<RRA>). An archive consists of a number of data values or statistics for
 each of the defined data-sources (B<DS>) and is defined with an B<RRA> line.
 
-When data is entered into an B<RRD>, it is first fit into time slots of
-the length defined with the B<-s> option becoming a I<primary data point>.
+When data is entered into an B<RRD>, it is first fit into time slots
+of the length defined with the B<-s> option, thus becoming a I<primary
+data point>.
 
-The data is also processed with the consolidation function (I<CF>)
-of the archive. There are several consolidation functions that consolidate
-primary data points via an aggregate function: B<AVERAGE>, B<MIN>, B<MAX>, B<LAST>.
-The format of B<RRA> line for these consolidation functions is:
+The data is also processed with the consolidation function (I<CF>) of
+the archive. There are several consolidation functions that
+consolidate primary data points via an aggregate function: B<AVERAGE>,
+B<MIN>, B<MAX>, B<LAST>. The format of B<RRA> line for these
+consolidation functions is:
 
 B<RRA:>I<AVERAGE | MIN | MAX | LAST>B<:>I<xff>B<:>I<steps>B<:>I<rows>
 
 I<xff> The xfiles factor defines what part of a consolidation interval may
 be made up from I<*UNKNOWN*> data while the consolidated value is still
-regarded as known.
+regarded as known. It is given as the ratio of allowed I<*UNKNOWN*> PDPs
+to the number of PDPs in the interval. Thus, it ranges from 0 to 1 (exclusive).
+
 
 I<steps> defines how many of these I<primary data points> are used to build
 a I<consolidated data point> which then goes into the archive.
@@ -189,52 +193,60 @@ I<rows> defines how many generations of data values are kept in an B<RRA>.
 
 =head1 Aberrant Behavior Detection with Holt-Winters Forecasting
 
-by Jake Brutlag E<lt>jakeb@corp.webtv.netE<gt>
-
 In addition to the aggregate functions, there are a set of specialized
 functions that enable B<RRDtool> to provide data smoothing (via the
-Holt-Winters forecasting algorithm), confidence bands, and the flagging
-aberrant behavior in the data source time series:
+Holt-Winters forecasting algorithm), confidence bands, and the
+flagging aberrant behavior in the data source time series:
 
-=over 4
+=over
 
-=item B<RRA:>I<HWPREDICT>B<:>I<rows>B<:>I<alpha>B<:>I<beta>B<:>I<seasonal period>B<:>I<rra-num>
+=item *
 
-=item B<RRA:>I<SEASONAL>B<:>I<seasonal period>B<:>I<gamma>B<:>I<rra-num>
+B<RRA:>I<HWPREDICT>B<:>I<rows>B<:>I<alpha>B<:>I<beta>B<:>I<seasonal period>[B<:>I<rra-num>]
 
-=item B<RRA:>I<DEVSEASONAL>B<:>I<seasonal period>B<:>I<gamma>B<:>I<rra-num>
+=item *
+
+B<RRA:>I<SEASONAL>B<:>I<seasonal period>B<:>I<gamma>B<:>I<rra-num>
 
-=item B<RRA:>I<DEVPREDICT>B<:>I<rows>B<:>I<rra-num>
+=item *
 
-=item B<RRA:>I<FAILURES>B<:>I<rows>B<:>I<threshold>B<:>I<window length>B<:>I<rra-num>
+B<RRA:>I<DEVSEASONAL>B<:>I<seasonal period>B<:>I<gamma>B<:>I<rra-num>
+
+=item *
+
+B<RRA:>I<DEVPREDICT>B<:>I<rows>B<:>I<rra-num>
+
+=item *
+
+B<RRA:>I<FAILURES>B<:>I<rows>B<:>I<threshold>B<:>I<window length>B<:>I<rra-num>
 
 =back
 
 These B<RRAs> differ from the true consolidation functions in several ways.
 First, each of the B<RRA>s is updated once for every primary data point.
 Second, these B<RRAs> are interdependent. To generate real-time confidence
-bounds, then a matched set of HWPREDICT, SEASONAL, DEVSEASONAL, and
+bounds, a matched set of HWPREDICT, SEASONAL, DEVSEASONAL, and
 DEVPREDICT must exist. Generating smoothed values of the primary data points
 requires both a HWPREDICT B<RRA> and SEASONAL B<RRA>. Aberrant behavior
 detection requires FAILURES, HWPREDICT, DEVSEASONAL, and SEASONAL.
 
 The actual predicted, or smoothed, values are stored in the HWPREDICT
-B<RRA>. The predicted deviations are store in DEVPREDICT (think a standard
+B<RRA>. The predicted deviations are stored in DEVPREDICT (think a standard
 deviation which can be scaled to yield a confidence band). The FAILURES
-B<RRA> stores binary indicators. A 1 marks the indexed observation a
+B<RRA> stores binary indicators. A 1 marks the indexed observation as
 failure; that is, the number of confidence bounds violations in the
 preceding window of observations met or exceeded a specified threshold. An
 example of using these B<RRAs> to graph confidence bounds and failures
 appears in L<rrdgraph>.
 
 The SEASONAL and DEVSEASONAL B<RRAs> store the seasonal coefficients for the
-Holt-Winters forecasting algorithm and the seasonal deviations respectively.
+Holt-Winters forecasting algorithm and the seasonal deviations, respectively.
 There is one entry per observation time point in the seasonal cycle. For
-example, if primary data points are generated every five minutes, and the
-seasonal cycle is 1 day, both SEASONAL and DEVSEASONAL with have 288 rows.
+example, if primary data points are generated every five minutes and the
+seasonal cycle is 1 day, both SEASONAL and DEVSEASONAL will have 288 rows.
 
 In order to simplify the creation for the novice user, in addition to
-supporting explicit creation the HWPREDICT, SEASONAL, DEVPREDICT,
+supporting explicit creation of the HWPREDICT, SEASONAL, DEVPREDICT,
 DEVSEASONAL, and FAILURES B<RRAs>, the B<RRDtool> create command supports
 implicit creation of the other four when HWPREDICT is specified alone and
 the final argument I<rra-num> is omitted.
@@ -247,7 +259,7 @@ default number of rows is the same as the HWPREDICT I<rows> argument. If the
 FAILURES B<RRA> is implicitly created, I<rows> will be set to the I<seasonal
 period> argument of the HWPREDICT B<RRA>. Of course, the B<RRDtool>
 I<resize> command is available if these defaults are not sufficient and the
-create wishes to avoid explicit creations of the other specialized function
+creator wishes to avoid explicit creations of the other specialized function
 B<RRAs>.
 
 I<seasonal period> specifies the number of primary data points in a seasonal
@@ -257,11 +269,11 @@ they are explicitly created, the creator should verify that all three
 I<seasonal period> arguments agree.
 
 I<alpha> is the adaption parameter of the intercept (or baseline)
-coefficient in the Holt-Winters forecasting algorithm. See L<RRDtool> for a
+coefficient in the Holt-Winters forecasting algorithm. See L<rrdtool> for a
 description of this algorithm. I<alpha> must lie between 0 and 1. A value
 closer to 1 means that more recent observations carry greater weight in
-predicting the baseline component of the forecast. A value closer to 0 mean
-that past history carries greater weight in predicted the baseline
+predicting the baseline component of the forecast. A value closer to 0 means
+that past history carries greater weight in predicting the baseline
 component.
 
 I<beta> is the adaption parameter of the slope (or linear trend) coefficient
@@ -286,25 +298,26 @@ be the same for both. Note that I<gamma> can also be changed via the
 B<RRDtool> I<tune> command.
 
 I<rra-num> provides the links between related B<RRAs>. If HWPREDICT is
-specified alone and the other B<RRAs> created implicitly, then there is no
-need to worry about this argument. If B<RRAs> are created explicitly, then
-pay careful attention to this argument. For each B<RRA> which includes this
-argument, there is a dependency between that B<RRA> and another B<RRA>. The
-I<rra-num> argument is the 1-based index in the order of B<RRA> creation
-(that is, the order they appear in the I<create> command). The dependent
-B<RRA> for each B<RRA> requiring the I<rra-num> argument is listed here:
+specified alone and the other B<RRAs> are created implicitly, then
+there is no need to worry about this argument. If B<RRAs> are created
+explicitly, then carefully pay attention to this argument. For each
+B<RRA> which includes this argument, there is a dependency between
+that B<RRA> and another B<RRA>. The I<rra-num> argument is the 1-based
+index in the order of B<RRA> creation (that is, the order they appear
+in the I<create> command). The dependent B<RRA> for each B<RRA>
+requiring the I<rra-num> argument is listed here:
 
-=over 4
+=over
 
 =item *
 
 HWPREDICT I<rra-num> is the index of the SEASONAL B<RRA>.
 
-=item * 
+=item *
 
 SEASONAL I<rra-num> is the index of the HWPREDICT B<RRA>.
 
-=item * 
+=item *
 
 DEVPREDICT I<rra-num> is the index of the DEVSEASONAL B<RRA>.
 
@@ -312,7 +325,7 @@ DEVPREDICT I<rra-num> is the index of the DEVSEASONAL B<RRA>.
 
 DEVSEASONAL I<rra-num> is the index of the HWPREDICT B<RRA>.
 
-=item * 
+=item *
 
 FAILURES I<rra-num> is the index of the DEVSEASONAL B<RRA>.
 
@@ -335,7 +348,7 @@ It may help you to sort out why all this *UNKNOWN* data is popping
 up in your databases:
 
 RRDtool gets fed samples at arbitrary times. From these it builds Primary
-Data Points (PDPs) at exact times every "step" interval. The PDPs are
+Data Points (PDPs) at exact times on every "step" interval. The PDPs are
 then accumulated into RRAs.
 
 The "heartbeat" defines the maximum acceptable interval between
@@ -350,7 +363,7 @@ The known rates during a PDP's "step" interval are used to calculate
 an average rate for that PDP. Also, if the total "unknown" time during
 the "step" interval exceeds the "heartbeat", the entire PDP is marked
 as "unknown". This means that a mixture of known and "unknown" sample
-time in a single PDP "step" may or may not add up to enough "unknown"
+times in a single PDP "step" may or may not add up to enough "unknown"
 time to exceed "heartbeat" and hence mark the whole PDP "unknown". So
 "heartbeat" is not only the maximum acceptable interval between
 samples, but also the maximum acceptable amount of "unknown" time per
@@ -367,6 +380,44 @@ sample. An extreme example of this might be a "step" of 5 minutes and a
 result in all the PDPs for that entire day period being set to the
 same average rate. I<-- Don Baarda E<lt>don.baarda@baesystems.comE<gt>>
 
+       time|
+       axis|
+ begin__|00|
+        |01|
+       u|02|----* sample1, restart "hb"-timer
+       u|03|   /
+       u|04|  /
+       u|05| /
+       u|06|/     "hbt" expired
+       u|07|
+        |08|----* sample2, restart "hb" 
+        |09|   / 
+        |10|  /
+       u|11|----* sample3, restart "hb"
+       u|12|   /
+       u|13|  /
+ step1_u|14| /
+       u|15|/     "swt" expired
+       u|16|
+        |17|----* sample4, restart "hb", create "pdp" for step1 = 
+        |18|   /  = unknown due to 10 "u" labled secs > "hb"
+        |19|  /
+        |20| /
+        |21|----* sample5, restart "hb"
+        |22|   /
+        |23|  /
+        |24|----* sample6, restart "hb"
+        |25|   /
+        |26|  /
+        |27|----* sample7, restart "hb"
+ step2__|28|   /
+        |22|  /
+        |23|----* sample8, restart "hb", create "pdp" for step1, create "cdp" 
+        |24|   /
+        |25|  /
+
+graphics by I<vladimir.lavrov@desy.de>.
+
 
 =head1 HOW TO MEASURE
 
@@ -377,17 +428,17 @@ Here are a few hints on how to measure:
 
 =item Temperature
 
-Normally you have some type of meter you can read to get the temperature.
+Usually you have some type of meter you can read to get the temperature.
 The temperature is not really connected with a time. The only connection is
 that the temperature reading happened at a certain time. You can use the
-B<GAUGE> data source type for this. RRDtool will the record your reading
+B<GAUGE> data source type for this. RRDtool will then record your reading
 together with the time.
 
 =item Mail Messages
 
 Assume you have a method to count the number of messages transported by
-your mailserver in a certain amount of time, this give you data like '5
-messages in the last 65 seconds'. If you look at the count of 5 like and
+your mailserver in a certain amount of time, giving you data like '5
+messages in the last 65 seconds'. If you look at the count of 5 like an
 B<ABSOLUTE> data type you can simply update the RRD with the number 5 and the
 end time of your monitoring period. RRDtool will then record the number of
 messages per second. If at some later stage you want to know the number of
@@ -398,87 +449,91 @@ precision should be acceptable.
 
 =item It's always a Rate
 
-RRDtool stores rates in amount/second for COUNTER, DERIVE and ABSOLUTE data.
-When you plot the data, you will get on the y axis amount/second which you
-might be tempted to convert to absolute amount volume by multiplying by the
-delta-time between the points. RRDtool plots continuous data, and as such is
-not appropriate for plotting absolute volumes as for example "total bytes"
-sent and received in a router. What you probably want is plot rates that you
-can scale to for example bytes/hour or plot volumes with another tool that
-draws bar-plots, where the delta-time is clear on the plot for each point
-(such that when you read the graph you see for example GB on the y axis,
-days on the x axis and one bar for each day).
+RRDtool stores rates in amount/second for COUNTER, DERIVE and ABSOLUTE
+data.  When you plot the data, you will get on the y axis
+amount/second which you might be tempted to convert to an absolute
+amount by multiplying by the delta-time between the points. RRDtool
+plots continuous data, and as such is not appropriate for plotting
+absolute amounts as for example "total bytes" sent and received in a
+router. What you probably want is plot rates that you can scale to
+bytes/hour, for example, or plot absolute amounts with another tool
+that draws bar-plots, where the delta-time is clear on the plot for
+each point (such that when you read the graph you see for example GB
+on the y axis, days on the x axis and one bar for each day).
 
 =back
 
 
 =head1 EXAMPLE
 
-C<rrdtool create temperature.rrd --step 300 DS:temp:GAUGE:600:-273:5000
-RRA:AVERAGE:0.5:1:1200 RRA:MIN:0.5:12:2400 RRA:MAX:0.5:12:2400
-RRA:AVERAGE:0.5:12:2400>
+ rrdtool create temperature.rrd --step 300 \
+  DS:temp:GAUGE:600:-273:5000 \
+  RRA:AVERAGE:0.5:1:1200 \
+  RRA:MIN:0.5:12:2400 \
+  RRA:MAX:0.5:12:2400 \
+  RRA:AVERAGE:0.5:12:2400
 
 This sets up an B<RRD> called F<temperature.rrd> which accepts one
 temperature value every 300 seconds. If no new data is supplied for
 more than 600 seconds, the temperature becomes I<*UNKNOWN*>.  The
-minimum acceptable value is -273 and the maximum is 5000.
+minimum acceptable value is -273 and the maximum is 5'000.
 
-A few archives areas are also defined. The first stores the
-temperatures supplied for 100 hours (1200 * 300 seconds = 100
+A few archive areas are also defined. The first stores the
+temperatures supplied for 100 hours (1'200 * 300 seconds = 100
 hours). The second RRA stores the minimum temperature recorded over
-every hour (12 * 300 seconds = 1 hour), for 100 days (2400 hours). The
+every hour (12 * 300 seconds = 1 hour), for 100 days (2'400 hours). The
 third and the fourth RRA's do the same for the maximum and
 average temperature, respectively.
 
 =head1 EXAMPLE 2
 
-C<rrdtool create monitor.rrd --step 300 
-DS:ifOutOctets:COUNTER:1800:0:4294967295
-RRA:AVERAGE:0.5:1:2016
-RRA:HWPREDICT:1440:0.1:0.0035:288>
+ rrdtool create monitor.rrd --step 300        \
+   DS:ifOutOctets:COUNTER:1800:0:4294967295   \
+   RRA:AVERAGE:0.5:1:2016                     \
+   RRA:HWPREDICT:1440:0.1:0.0035:288
 
 This example is a monitor of a router interface. The first B<RRA> tracks the
 traffic flow in octets; the second B<RRA> generates the specialized
 functions B<RRAs> for aberrant behavior detection. Note that the I<rra-num>
-argument of HWPREDICT is missing, so the other B<RRAs> will be implicitly be
+argument of HWPREDICT is missing, so the other B<RRAs> will implicitly be
 created with default parameter values. In this example, the forecasting
 algorithm baseline adapts quickly; in fact the most recent one hour of
-observations (each at 5 minute intervals) account for 75% of the baseline
+observations (each at 5 minute intervals) accounts for 75% of the baseline
 prediction. The linear trend forecast adapts much more slowly. Observations
-made in during the last day (at 288 observations per day) account for only
+made during the last day (at 288 observations per day) account for only
 65% of the predicted linear trend. Note: these computations rely on an
-exponential smoothing formula described in a forthcoming LISA 2000 paper.
+exponential smoothing formula described in the LISA 2000 paper.
 
 The seasonal cycle is one day (288 data points at 300 second intervals), and
 the seasonal adaption parameter will be set to 0.1. The RRD file will store 5
-days (1440 data points) of forecasts and deviation predictions before wrap
+days (1'440 data points) of forecasts and deviation predictions before wrap
 around. The file will store 1 day (a seasonal cycle) of 0-1 indicators in
 the FAILURES B<RRA>.
 
-The same RRD file and B<RRAs> are created with the following command, which explicitly
-creates all specialized function B<RRAs>.
+The same RRD file and B<RRAs> are created with the following command,
+which explicitly creates all specialized function B<RRAs>.
 
-C<rrdtool create monitor.rrd --step 300 
-DS:ifOutOctets:COUNTER:1800:0:4294967295
-RRA:AVERAGE:0.5:1:2016
-RRA:HWPREDICT:1440:0.1:0.0035:288:3
-RRA:SEASONAL:288:0.1:2
-RRA:DEVPREDICT:1440:5
-RRA:DEVSEASONAL:288:0.1:2
-RRA:FAILURES:288:7:9:5>
+ rrdtool create monitor.rrd --step 300 \
+   DS:ifOutOctets:COUNTER:1800:0:4294967295 \
+   RRA:AVERAGE:0.5:1:2016 \
+   RRA:HWPREDICT:1440:0.1:0.0035:288:3 \
+   RRA:SEASONAL:288:0.1:2 \
+   RRA:DEVPREDICT:1440:5 \
+   RRA:DEVSEASONAL:288:0.1:2 \
+   RRA:FAILURES:288:7:9:5
 
-Of course, explicit creation need not replicate implicit create, a number of arguments 
-could be changed.
+Of course, explicit creation need not replicate implicit create, a
+number of arguments could be changed.
 
 =head1 EXAMPLE 3
 
-C<rrdtool create proxy.rrd --step 300 
-DS:TotalRequests:DERIVE:1800:0:U
-DS:AccumDuration:DERIVE:1800:0:U
-DS:AvgReqDuration:COMPUTE:AccumDuration,TotalRequests,0,EQ,1,TotalRequests,IF,/
-RRA:AVERAGE:0.5:1:2016>
+ rrdtool create proxy.rrd --step 300 \
+   DS:Total:DERIVE:1800:0:U  \
+   DS:Duration:DERIVE:1800:0:U  \
+   DS:AvgReqDur:COMPUTE:Duration,Requests,0,EQ,1,Requests,IF,/ \
+   RRA:AVERAGE:0.5:1:2016
 
-This example is monitoring the average request duration during each 300 sec 
+This example is monitoring the average request duration during each 300 sec
 interval for requests processed by a web proxy during the interval.
 In this case, the proxy exposes two counters, the number of requests
 processed since boot and the total cumulative duration of all processed
@@ -495,4 +550,4 @@ RPN expression handles the divide by zero case.
 
 =head1 AUTHOR
 
-Tobias Oetiker E<lt>oetiker@ee.ethz.chE<gt>
+Tobias Oetiker E<lt>tobi@oetiker.chE<gt>
index de6b0ecea91e018c5024b9860d115037f5d779a7..2e4cd4b2419138bab805a718c130597935a45e4c 100644 (file)
@@ -1,20 +1,23 @@
 =head1 NAME
 
-rrdtool dump - dump the contents of an B<RRD> to XML format
-
-=for html <div align="right"><a href="rrddump.pdf">PDF</a> version.</div>
+rrddump - dump the contents of an RRD to XML format
 
 =head1 SYNOPSIS
 
-B<rrdtool> B<dump> I<filename.rrd> E<gt> I<filename.xml> 
+B<rrdtool> B<dump> I<filename.rrd> E<gt> I<filename.xml>
+
+or 
+
+B<rrdtool> B<dump> I<filename.rrd> I<filename.xml>
 
 =head1 DESCRIPTION
 
-The B<dump> function prints the contents of an B<RRD> in human
-readable (?) XML format. This format can be read by rrdrestore.
-Together they allow you to transfer your files from one architecture
-to another as well as manipulating the contents of an B<RRD> file in a
-somewhat more convenient manner.
+The B<dump> function writes the contents of an B<RRD> in human
+readable (?) XML format to a file or to stdout. This format can
+be read by rrdrestore. Together they allow you to transfer your
+files from one computer architecture to another as well to
+manipulate the contents of an B<RRD> file in a somewhat more
+convenient manner.
 
 
 
@@ -24,6 +27,11 @@ somewhat more convenient manner.
 
 The name of the B<RRD> you want to dump.
 
+=item I<filename.xml>
+
+The (optional) filename that you want to write the XML output to.
+If not specified, the XML will be printed to stdout.
+
 =back
 
 =head1 EXAMPLES
@@ -37,18 +45,18 @@ To transfer an RRD between architectures, follow these steps:
 On the same system where the RRD was created, use B<rrdtool> B<dump>
 to export the data to XML format.
 
-=item 2. 
+=item 2.
 
-Transfer the XML dump to the target system
+Transfer the XML dump to the target system.
 
 =item 3.
 
-Run B<rrdtool> B<restore> to create a new RRD from the XML dump.  See
+Run B<rrdtool> B<restore> to create a new RRD from the XML dump. See
 B<rrdrestore> for details.
 
 =back
 
 =head1 AUTHOR
 
-Tobias Oetiker E<lt>oetiker@ee.ethz.chE<gt>
+Tobias Oetiker E<lt>tobi@oetiker.chE<gt>
 
index a4e87c54d10bc15bfa53440464c8a49d70cc0d88..51b5ccd99c8441f8f7f12021836ba22a902ccc56 100644 (file)
@@ -1,62 +1,60 @@
 =head1 NAME
 
-rrdtool fetch - fetch data from an RRD.
-
-=for html <div align="right"><a href="rrdfetch.pdf">PDF</a> version.</div>
+rrdfetch - Fetch data from an RRD.
 
 =head1 SYNOPSIS
 
-B<rrdtool> B<fetch> I<filename> I<CF> 
-S<[B<--resolution>|B<-r> I<resolution>]> 
-S<[B<--start>|B<-s> I<start>]> 
-S<[B<--end>|B<-e> I<end>]> 
+B<rrdtool> B<fetch> I<filename> I<CF>
+S<[B<--resolution>|B<-r> I<resolution>]>
+S<[B<--start>|B<-s> I<start>]>
+S<[B<--end>|B<-e> I<end>]>
 
 =head1 DESCRIPTION
 
-The B<fetch> function is normally used internally by the graph function,
-to get data from B<RRD>s. B<fetch> will analyze the B<RRD> and
-will try to retrieve the data in the resolution requested.
+The B<fetch> function is normally used internally by the graph
+function to get data from B<RRD>s. B<fetch> will analyze the B<RRD>
+and try to retrieve the data in the resolution requested.
 The data fetched is printed to stdout. I<*UNKNOWN*> data is often
 represented by the string "NaN" depending on your OS's printf
 function.
 
 =over 8
 
-=item I<filename> 
+=item I<filename>
 
 the name of the B<RRD> you want to fetch the data from.
 
-=item I<CF> 
+=item I<CF>
 
-which consolidation function should have been applied to the data you
-want to fetch? (AVERAGE,MIN,MAX,LAST)
+the consolidation function that is applied to the data you
+want to fetch (AVERAGE,MIN,MAX,LAST)
 
 =item B<--resolution>|B<-r> I<resolution> (default is the highest resolution)
 
-what interval should the values have (seconds per value). B<rrdfetch> will try
-to match your request, but it will return data even if no absolute
-match is possible. B<NB.> See note below.
+the interval you want the values to have (seconds per
+value). B<rrdfetch> will try to match your request, but it will return
+data even if no absolute match is possible. B<NB.> See note below.
 
 =item B<--start>|B<-s> I<start> (default end-1day)
 
-when should the data begin. A time in seconds since epoch (1970-01-01)
-is required. Negative numbers are relative to the current time. By default
+start of the time series. A time in seconds since epoch (1970-01-01)
+is required. Negative numbers are relative to the current time. By default,
 one day worth of data will be fetched. See also AT-STYLE TIME SPECIFICATION
-section for a detailed explanation on  ways to specify start time.
+section for a detailed explanation on  ways to specify the start time.
 
 =item B<--end>|B<-e> I<end> (default now)
 
-when should the data end. Time in seconds since epoch. See also
-AT-STYLE TIME SPECIFICATION section for a detailed explanation of how to specify
-end time.
+the end of the time series in seconds since epoch. See also AT-STYLE
+TIME SPECIFICATION section for a detailed explanation of how to
+specify the end time.
 
 =back
 
 =head2 RESOLUTION INTERVAL
 
-In order to get RRDtool to fetch anything other than the finest resolution RRA 
-B<both> the start and end time must be specified on boundaries that are 
-multiples of the wanted resolution. Consider the following example:
+In order to get RRDtool to fetch anything other than the finest resolution RRA
+B<both> the start and end time must be specified on boundaries that are
+multiples of the desired resolution. Consider the following example:
 
  rrdtool create subdata.rrd -s 10 DS:ds0:GAUGE:300:0:U \
   RRA:AVERAGE:0.5:30:3600 \
@@ -66,17 +64,19 @@ multiples of the wanted resolution. Consider the following example:
   RRA:AVERAGE:0.5:8640:600 \
   RRA:MAX:0.5:8640:600
 
-This RRD collects data every 10 seconds and stores its averages over 5 minutes, 
-15 minutes, 1 hour and 1 day as well as the maxima for 1 hour and 1 day.
+This RRD collects data every 10 seconds and stores its averages over 5
+minutes, 15 minutes, 1 hour, and 1 day, as well as the maxima for 1 hour
+and 1 day.
 
-Consider now that you want too fetch the 15 minute average data for last hour. 
-So you might try
+Consider now that you want to fetch the 15 minute average data for the
+last hour.  You might try
 
  rrdtool fetch subdata.rrd AVERAGE -r 900 -s -1h
 
-However, this will almost always result in a time series that is B<NOT> in the 15 
-minute RRA. Therefore the highest resolution RRA, i.e. 5 minute averages, will 
-be chosen which, in this case, is not what you want.
+However, this will almost always result in a time series that is
+B<NOT> in the 15 minute RRA. Therefore, the highest resolution RRA,
+i.e. 5 minute averages, will be chosen which in this case is not
+what you want.
 
 Hence, make sure that
 
@@ -88,110 +88,116 @@ both start and end time are a multiple of 900
 
 =item 2.
 
-both start and end time are within the wanted RRA
+both start and end time are within the desired RRA
 
 =back
 
-So, if time now is called "t",
+So, if time now is called "t", do
 
- do end time == int(t/900)*900,
- start time == end time -1hour, resolution == 900.
+ end time == int(t/900)*900,
+ start time == end time - 1hour,
+ resolution == 900.
 
-In e.g. bash this could look as:
+Using the bash shell, this could look be:
 
- TIME=$(date +%s); RRDRES=900; rrdtool fetch subdata.rrd AVERAGE -r $RRDRES \
- -e $(echo $(($TIME/$RRDRES*$RRDRES))) -s e-1h
+ TIME=$(date +%s)
+ RRDRES=900
+ rrdtool fetch subdata.rrd AVERAGE -r $RRDRES \
+    -e $(($TIME/$RRDRES*$RRDRES)) -s e-1h
 
 Or in Perl:
 
- perl -e '$ctime = time; $rrdres = 900; system "rrdtool fetch subdata.rrd AVERAGE \
- -r $rrdres -e @{[int($ctime/$rrdres)*$rrdres]} -s e-1h"'
+ perl -e '$ctime = time; $rrdres = 900; \
+          system "rrdtool fetch subdata.rrd AVERAGE \
+                  -r $rrdres -e @{[int($ctime/$rrdres)*$rrdres]} -s e-1h"'
 
 
 =head2 AT-STYLE TIME SPECIFICATION
 
 Apart from the traditional I<Seconds since epoch>, RRDtool does also
-understand at-style time specification.  The specification is called
-"at-style" after Unix command at(1) that has moderately complex ways
-to specify time to run your job at.  The at-style specification
-consists of two parts: B<TIME REFERENCE> specification and B<TIME
-OFFSET> specification.
+understand at-style time specification. The specification is called
+"at-style" after the Unix command at(1) that has moderately complex
+ways to specify time to run your job at a certain date and time. The
+at-style specification consists of two parts: the B<TIME REFERENCE>
+specification and the B<TIME OFFSET> specification.
 
 =head2 TIME REFERENCE SPECIFICATION
 
-Time reference specification is used, well,... to establish a reference
-moment in time (for time offset to be applied to). When present,
+The time reference specification is used, well, to establish a reference
+moment in time (to which the time offset is then applied to). When present,
 it should come first, when omitted, it defaults to B<now>. On its own part,
-time reference consists of I<time-of-day> reference (which should come
-first, if present) and I<day> reference.
+time reference consists of I<time-of-day> reference (which should come
+first, if present) and I<day> reference.
 
-I<Time-of-day> can be specified as B<HH:MM>, B<HH.MM>,
-or just B<HH>, you can suffix it with B<am> or B<pm> or use
-24-hours clock. The few special times of day are understood as well,
-these include B<midnight> (00:00), B<noon> (12:00) and British
+The I<time-of-day> can be specified as B<HH:MM>, B<HH.MM>,
+or just B<HH>. You can suffix it with B<am> or B<pm> or use
+24-hours clock. Some special times of day are understood as well,
+including B<midnight> (00:00), B<noon> (12:00) and British
 B<teatime> (16:00).
 
-The I<day> can be specified as I<month-name> I<day-of-the-month>
-and optional 2- or 4-digit I<year> number (e.g. March 8 1999).
-Alternatively, you can use I<day-of-week-name> (e.g. Monday),
-or one of the words: B<yesterday>, B<today>, B<tomorrow>.
-You can also specify I<day> as a full date in several numerical formats;
-these include: B<MM/DD/[YY]YY>, B<DD.MM.[YY]YY>, B<YYYYMMDD>.
+The I<day> can be specified as I<month-name> I<day-of-the-month> and
+optional a 2- or 4-digit I<year> number (e.g. March 8 1999). Alternatively,
+you can use I<day-of-week-name> (e.g. Monday), or one of the words:
+B<yesterday>, B<today>, B<tomorrow>. You can also specify the I<day> as a
+full date in several numerical formats, including B<MM/DD/[YY]YY>,
+B<DD.MM.[YY]YY>, or B<YYYYMMDD>.
 
-I<NOTE1>: this is different from the original at(1) behavior,
-which interprets a single-number date as MMDD[YY]YY.
+I<NOTE1>: this is different from the original at(1) behavior, where a
+single-number date is interpreted as MMDD[YY]YY.
 
-I<NOTE2>: if you specify I<day> this way, the I<time-of-day> is REQUIRED
-to be present.
+I<NOTE2>: if you specify the I<day> in this way, the I<time-of-day> is
+REQUIRED as well.
 
-Finally, you can use words B<now>, B<start>, or B<end> as your time
-reference. B<Now> refers to the current moment (and is also a default
-time reference). B<Start> (B<end>) can be used to specify time
+Finally, you can use the words B<now>, B<start>, or B<end> as your time
+reference. B<Now> refers to the current moment (and is also the default
+time reference). B<Start> (B<end>) can be used to specify time
 relative to the start (end) time for those tools that use these
 categories (B<rrdfetch>, L<rrdgraph>).
 
-Month and weekday names can be used in their naturally abbreviated form
-(e.g., Dec for December, Sun for Sunday, etc.). The words B<now>,
-B<start>, B<end> can be abbreviated to B<n>, B<s>, B<e>.
+Month and day of the week names can be used in their naturally
+abbreviated form (e.g., Dec for December, Sun for Sunday, etc.). The
+words B<now>, B<start>, B<end> can be abbreviated as B<n>, B<s>, B<e>.
 
 =head2 TIME OFFSET SPECIFICATION
 
-Time offset specification is used to add (or subtract) certain time
-interval to (from) the time reference moment. It consists of I<sign>
-(S<B<+> or B<->>) and I<amount>. The following time units can be used
-to specify the I<amount>: B<years>, B<months>, B<weeks>, B<days>,
-B<hours>, B<minutes>, B<seconds>, these can be used in singular
-or plural form, and abbreviated naturally or to a single letter
-(e.g. +3days, -1wk, -3y). Several time units can be combined
-together (e.g., -5mon1w2d), as well as several time offsets can be
-concatenated (e.g., -5h45min = -5h-45min = -6h+15min = -7h+1h30m-15min, etc.)
+The time offset specification is used to add/subtract certain time
+intervals to/from the time reference moment. It consists of a I<sign>
+(S<B<+> or B<->>) and an I<amount>. The following time units can be
+used to specify the I<amount>: B<years>, B<months>, B<weeks>, B<days>,
+B<hours>, B<minutes>, or B<seconds>. These units can be used in
+singular or plural form, and abbreviated naturally or to a single
+letter (e.g. +3days, -1wk, -3y). Several time units can be combined
+(e.g., -5mon1w2d) or concatenated (e.g., -5h45min = -5h-45min =
+-6h+15min = -7h+1h30m-15min, etc.)
 
 I<NOTE3>: If you specify time offset in days, weeks, months, or years,
-you will end with the time offset that may vary depending on you time
+you will end with the time offset that may vary depending on your time
 reference, because all those time units have no single well defined
 time interval value (S<1 year> contains either 365 or 366 days, S<1 month>
 is 28 to 31 days long, and even S<1 day> may be not equal to 24 hours
 twice a year, when DST-related clock adjustments take place).
 To cope with this, when you use days, weeks, months, or years
 as your time offset units your time reference date is adjusted
-accordingly without taking too much further effort to ensure anything
+accordingly without too much further effort to ensure anything
 about it (in the hope that mktime(3) will take care of this later).
 This may lead to some surprising (or even invalid!) results,
 e.g. S<'May 31 -1month'> = S<'Apr 31'> (meaningless) = S<'May 1'>
 (after mktime(3) normalization); in the EET timezone
 '3:30am Mar 29 1999 -1 day' yields '3:30am Mar 28 1999' (Sunday)
-which is invalid time/date combination (because of 3am -> 4am DST
+which is an invalid time/date combination (because of 3am -> 4am DST
 forward clock adjustment, see the below example).
-On the other hand, hours, minutes, and seconds are well defined time
+
+In contrast, hours, minutes, and seconds are well defined time
 intervals, and these are guaranteed to always produce time offsets
-exactly as specified (e.g. for EET timezone, S<'8:00 Mar 27 1999 +2 days'> =
-S<'8:00 Mar 29 1999'>, but since there is 1-hour DST forward clock adjustment
-takes place around S<3:00 Mar 28 1999>, the actual time interval between
-S<8:00 Mar 27 1999> and S<8:00 Mar 29 1999> equals 47 hours; on the other hand,
-S<'8:00 Mar 27 1999 +48 hours'> = S<'9:00 Mar 29 1999'>, as expected)
+exactly as specified (e.g. for EET timezone, S<'8:00 Mar 27 1999 +2
+days'> = S<'8:00 Mar 29 1999'>, but since there is 1-hour DST forward
+clock adjustment that occurs around S<3:00 Mar 28 1999>, the actual
+time interval between S<8:00 Mar 27 1999> and S<8:00 Mar 29 1999>
+equals 47 hours; on the other hand, S<'8:00 Mar 27 1999 +48 hours'> =
+S<'9:00 Mar 29 1999'>, as expected)
 
 I<NOTE4>: The single-letter abbreviation for both B<months> and B<minutes>
-is B<m>. To disambiguate, the parser tries to read your S<mind :)>
+is B<m>. To disambiguate them, the parser tries to read your S<mind :)>
 by applying the following two heuristics:
 
 =over 3
@@ -201,26 +207,26 @@ by applying the following two heuristics:
 If B<m> is used in context of (i.e. right after the) years,
 months, weeks, or days it is assumed to mean B<months>, while
 in the context of hours, minutes, and seconds it means minutes.
-(e.g., in -1y6m or +3w1m B<m> means B<months>, while in
--3h20m or +5s2m B<m> means B<minutes>)
+(e.g., in -1y6m or +3w1m B<m> is interpreted as B<months>, while in
+-3h20m or +5s2m B<m> the parser decides for B<minutes>).
 
 =item 2
 
 Out of context (i.e. right after the B<+> or B<-> sign) the
 meaning of B<m> is guessed from the number it directly follows.
-Currently, if the number absolute value is below 25 it is assumed
+Currently, if the number's absolute value is below 25 it is assumed
 that B<m> means B<months>, otherwise it is treated as B<minutes>.
 (e.g., -25m == -25 minutes, while +24m == +24 months)
 
 =back
 
 I<Final NOTES>: Time specification is case-insensitive.
-Whitespace can be inserted freely or omitted altogether,
-there are, however, cases when whitespace is required
+Whitespace can be inserted freely or omitted altogether.
+There are, however, cases when whitespace is required
 (e.g., S<'midnight Thu'>). In this case you should either quote the
 whole phrase to prevent it from being taken apart by your shell or use
 '_' (underscore) or ',' (comma) which also count as whitespace
-(e.g., midnight_Thu or midnight,Thu)
+(e.g., midnight_Thu or midnight,Thu).
 
 
 =head2 TIME SPECIFICATION EXAMPLES
@@ -228,29 +234,29 @@ whole phrase to prevent it from being taken apart by your shell or use
 I<Oct 12> -- October 12 this year
 
 I<-1month> or I<-1m> -- current time of day, only a month before
-(may yield surprises, see the NOTE3 above)
+(may yield surprises, see NOTE3 above).
 
-I<noon yesterday -3hours> -- yesterday morning; can be put also as I<9am-1day>
+I<noon yesterday -3hours> -- yesterday morning; can also be specified
+as I<9am-1day>.
 
-I<23:59 31.12.1999> -- 1 minute to the year 2000
+I<23:59 31.12.1999> -- 1 minute to the year 2000.
 
-I<12/31/99 11:59pm> -- 1 minute to the year 2000 for imperialists
+I<12/31/99 11:59pm> -- 1 minute to the year 2000 for imperialists.
 
 I<12am 01/01/01> -- start of the new millennium
 
 I<end-3weeks> or I<e-3w> -- 3 weeks before end time
-(may be used as start time specification)
+(may be used as start time specification).
 
 I<start+6hours> or I<s+6h> -- 6 hours after start time
-(may be used as end time specification)
+(may be used as end time specification).
 
 I<931225537> -- 18:45  July 5th, 1999
-(yes, seconds since 1970 are valid as well)
+(yes, seconds since 1970 are valid as well).
 
 I<19970703 12:45> -- 12:45  July 3th, 1997
-(my favorite, and its even got an ISO number (8601))
+(my favorite, and its even got an ISO number (8601)).
 
 =head1 AUTHOR
 
-Tobias Oetiker <oetiker@ee.ethz.ch>
-
+Tobias Oetiker <tobi@oetiker.ch>
index 4d01273ea6a8e7ed4852efdda5091aaafe3d6654..9a3c690848e9ec6554bc39ef810f440a772fb9cd 100644 (file)
@@ -1,8 +1,6 @@
 =head1 NAME
 
-rrdfirst - Return the date of the first data sample in an B<RRA> within an B<RRD>
-
-=for html <div align="right"><a href="rrdfirst.pdf">PDF</a> version.</div>
+rrdfirst - Return the date of the first data sample in an RRA within an RRD
 
 =head1 SYNOPSIS
 
@@ -10,8 +8,8 @@ B<rrdtool> B<first> I<filename> [I<--rraindex number>]
 
 =head1 DESCRIPTION
 
-The B<first> function returns the UNIX timestamp of the first data sample for
-the specified RRA of the RRD file.
+The B<first> function returns the UNIX timestamp of the first data
+sample entered into the specified RRA of the RRD file.
 
 =over 8
 
@@ -21,8 +19,8 @@ The name of the B<RRD> that contains the data.
 
 =item I<--rraindex number>
 
-The index number of the B<RRA> that is to be examined.  If not specified, the
-index defaults to zero. B<RRA> index numbers can be determined through 
+The index number of the B<RRA> that is to be examined. If not specified, the
+index defaults to zero. B<RRA> index numbers can be determined through
 B<rrdtool info>.
 
 =back
index 1043d6971b6346d879b5358466073c3148ca0011..f35e0cd4f6d6bd0876d2eb5161b0ae1efb4700d8 100644 (file)
@@ -2,12 +2,12 @@
 
 rrdtool graph - Create a graph based on data from one or several RRD
 
-=for html <div align="right"><a href="rrdgraph.pdf">PDF</a> version.</div> 
+=for html <div align="right"><a href="rrdgraph.pdf">PDF</a> version.</div>
 
 =head1 SYNOPSIS
 
-B<rrdtool> B<graph> I<filename> 
-S<[B<-s>|B<--start> I<seconds>]> 
+B<rrdtool> B<graph> I<filename>
+S<[B<-s>|B<--start> I<seconds>]>
 S<[B<-e>|B<--end> I<seconds>]>
 S<[B<-x>|B<--x-grid> I<x-axis grid and label>]>
 S<[B<-y>|B<--y-grid> I<y-axis grid and label>]>
@@ -17,13 +17,13 @@ S<[B<-M>|B<--alt-autoscale-max>]>
 S<[B<-X>|B<--units-exponent>]> I<value>]>
 S<[B<-v>|B<--vertical-label> I<text>]>
 S<[B<-w>|B<--width> I<pixels>]>
-S<[B<-h>|B<--height> I<pixels>]> 
-S<[B<-i>|B<--interlaced>]> 
-S<[B<-f>|B<--imginfo> I<formatstring>]> 
-S<[B<-a>|B<--imgformat> B<SVG>|B<PNG>]> 
-S<[B<-z>|B<--lazy>]> 
+S<[B<-h>|B<--height> I<pixels>]>
+S<[B<-i>|B<--interlaced>]>
+S<[B<-f>|B<--imginfo> I<formatstring>]>
+S<[B<-a>|B<--imgformat> B<SVG>|B<PNG>]>
+S<[B<-z>|B<--lazy>]>
 S<[B<-o>|B<--logarithmic>]>
-S<[B<-u>|B<--upper-limit> I<value>]> 
+S<[B<-u>|B<--upper-limit> I<value>]>
 S<[B<-l>|B<--lower-limit> I<value>]>
 S<[B<-g>|B<--no-legend>]>
 S<[B<-r>|B<--rigid>]>
@@ -51,7 +51,7 @@ from generating graphs, it can also extract numerical reports.
 
 =over
 
-=item I<filename> 
+=item I<filename>
 
 The name of the graph to generate. Since B<RRDtool> outputs
 SVGs and PNGs, it's recommended that the filename end in either
@@ -124,16 +124,16 @@ If you want no y-grid at all set specify the magic word B<none>.
 
 Place Y grid dynamically based on graph Y range. Algorithm ensures
 that you always have grid, that there are enough but not too many
-grid lines and the grid is metric. That is grid lines are placed 
+grid lines and the grid is metric. That is grid lines are placed
 every 1, 2, 5 or 10 units.  (contributed by Sasha Mikheev)
 
 
 =item B<--alt-autoscale>
 
-Compute Y range  based on function absolute minimum and 
-maximum values. Default algorithm uses predefined set of ranges.  
+Compute Y range  based on function absolute minimum and
+maximum values. Default algorithm uses predefined set of ranges.
 This is good in many cases but it fails miserably when you need
-to graph something like 260 + 0.001 * sin(x). Default algorithm 
+to graph something like 260 + 0.001 * sin(x). Default algorithm
 will use Y range from 250 to 300 and on the graph you will see
 almost straight line. With --alt-autoscale Y range will be
 from slightly less the 260 - 0.001 to slightly more then 260 + 0.001
@@ -142,7 +142,7 @@ and periodic behavior will be seen.   (contributed by Sasha Mikheev)
 =item B<--alt-autoscale-max>
 
 Where --alt-autoscale will modify both the absolute maximum AND minimum
-values, this option will only affect the maximum value. The minimum 
+values, this option will only affect the maximum value. The minimum
 value, if not defined on the command line, will be 0. This option can
 be useful when graphing router traffic when the WAN line uses compression,
 and thus the throughput may be higher than the WAN line speed.
@@ -196,7 +196,7 @@ would look like this:
 
 =item B<-a>|B<--imgformat> B<SVG>|B<PNG> (default: PNG)
 
-Allows you to produce PNG output from RRDtool. 
+Allows you to produce PNG output from RRDtool.
 
 =item B<-z>|B<--lazy> (default: false)
 
@@ -274,11 +274,11 @@ consolidated according to the consolidation function (I<CF>) chosen.
 
 Create a new virtual data source by evaluating a mathematical expression,
 specified in Reverse Polish Notation (RPN). If you have ever used a traditional
-HP calculator you already know RPN. The idea behind RPN notation is, 
+HP calculator you already know RPN. The idea behind RPN notation is,
 that you have a stack and push your data onto this stack. When ever
 you execute an operation, it takes as many data values from the stack
 as needed. The pushing of data is implicit, so when ever you specify a number
-or a variable, it gets pushed automatically. 
+or a variable, it gets pushed automatically.
 
 If this is all a big load of incomprehensible words for you, maybe an
 example helps (a more complete explanation is given in [1]): The
@@ -294,13 +294,13 @@ expression.
 
 The I<rpn-expression> in the B<CDEF> function takes both, constant values
 as well as I<vname> variables. The following operators can be used on these
-values: 
+values:
 
 =over
 
 =item +, -, *, /, %
 
-pops two values from the stack applies the selected operator and pushes 
+pops two values from the stack applies the selected operator and pushes
 the result back onto the stack. The % operator stands for the modulo
 operation.
 
@@ -362,9 +362,9 @@ perform calculations across the data.
 
 =item COUNT
 
-Pushes the number 1 if it is at the first value of the data set, the 
-number 2 if it is at the second, and so on. This special value, allows 
-you to make calculations based on the position of the value within 
+Pushes the number 1 if it is at the first value of the data set, the
+number 2 if it is at the second, and so on. This special value, allows
+you to make calculations based on the position of the value within
 the data set.
 
 =item INF, NEGINF
@@ -456,15 +456,15 @@ Draw a vertical rule into the graph and optionally add a legend
 =item B<LINE>{B<1>|B<2>|B<3>}B<:>I<vname>[B<#>I<rrggbb>[B<:>I<legend>]]
 
 Plot for the requested data, using the color specified. Write a legend
-into the graph. The 3 possible keywords B<LINE1>, B<LINE2>, and B<LINE3> 
-generate increasingly wide lines. If no color is defined, 
-the drawing is done 'blind' this is useful in connection with the 
-B<STACK> function when you want to ADD the values of two 
+into the graph. The 3 possible keywords B<LINE1>, B<LINE2>, and B<LINE3>
+generate increasingly wide lines. If no color is defined,
+the drawing is done 'blind' this is useful in connection with the
+B<STACK> function when you want to ADD the values of two
 data-sources without showing it in the graph.
 
 =item B<AREA>:I<vname>[B<#>I<rrggbb>[B<:>I<legend>]]
 
-Does the same as B<LINE?>, but the area between 0 and 
+Does the same as B<LINE?>, but the area between 0 and
 the graph will be filled with the color specified.
 
 =item B<STACK>:I<vname>[B<#>I<rrggbb>[B<:>I<legend>]]
@@ -474,7 +474,7 @@ B<LINE?>, B<AREA> or B<STACK> graph. Depending on the type of the
 previous graph, the B<STACK> will be either a B<LINE?> or an B<AREA>.
 This obviously implies that the first B<STACK> must be preceded by an
 B<AREA> or B<LINE?> -- you need something to stack something onto in
-the first place ;) 
+the first place ;)
 
 Note, that when you STACK onto *UNKNOWN* data, RRDtool will not draw
 any graphics ... *UNKNOWN* is not zero ... if you want it to be zero
@@ -551,15 +551,15 @@ doesn't match.
          CDEF:aggoutput=odat1,UN,0,odat1,IF,odat2,UN,0,odat2,IF,+,8,* \
          AREA:agginput#00cc00:Input Aggregate \
          LINE1:agginput#0000FF:Output Aggregate
-         
-Assuming that idat1 has a data value of I<*UNKNOWN*>, the CDEF expression 
 
- idat1,UN,0,idat1,IF 
+Assuming that idat1 has a data value of I<*UNKNOWN*>, the CDEF expression
+
+ idat1,UN,0,idat1,IF
 
 leaves us with a stack with contents of 1,0,NaN and the IF function
 will pop off the 3 values and replace them with 0.  If idat1 had a
 real value like 7942099, then the stack would have 0,0,7942099 and the
-real value would be the replacement.  
+real value would be the replacement.
 
 =head1 EXAMPLE 3
 
@@ -657,7 +657,7 @@ be misleading.
 
 =head1 AUTHOR
 
-Tobias Oetiker E<lt>oetiker@ee.ethz.chE<gt>
+Tobias Oetiker E<lt>tobi@oetiker.chE<gt>
 
 =head1 REFERENCES
 
diff --git a/doc/rrdgraph.pod b/doc/rrdgraph.pod
new file mode 100644 (file)
index 0000000..9060bd8
--- /dev/null
@@ -0,0 +1,398 @@
+=head1 NAME
+
+rrdgraph - Round Robin Database tool grapher functions
+
+=head1 SYNOPSIS
+
+B<rrdtool graph> I<filename>
+[I<L<option|rrdgraph/OPTIONS>> ...]
+[I<L<data definition|rrdgraph_data/DEF>> ...]
+[I<L<data calculation|rrdgraph_data/CDEF>> ...]
+[I<L<variable definition|rrdgraph_data/VDEF>> ...]
+[I<L<graph element|rrdgraph_graph/GRAPH>> ...]
+[I<L<print element|rrdgraph_graph/PRINT>> ...]
+
+=head1 DESCRIPTION
+
+The B<graph> function of B<RRDtool> is used to present the
+data from an B<RRD> to a human viewer.  Its main purpose is to
+create a nice graphical representation, but it can also generate
+a numerical report.
+
+=head1 OVERVIEW
+
+B<rrdtool graph> needs data to work with, so you must use one or more
+B<L<data definition|rrdgraph_data/DEF>> statements to collect this
+data.  You are not limited to one database, it's perfectly legal to
+collect data from two or more databases (one per statement, though).
+
+If you want to display averages, maxima, percentiles, etcetera
+it is best to collect them now using the
+B<L<variable definition|rrdgraph_data/VDEF>> statement.
+Currently this makes no difference, but in a future version
+of rrdtool you may want to collect these values before consolidation.
+
+The data fetched from the B<RRA> is then B<consolidated> so that
+there is exactly one datapoint per pixel in the graph. If you do
+not take care yourself, B<RRDtool> will expand the range slightly
+if necessary. Note, in that case the first and/or last pixel may very
+well become unknown!
+
+Sometimes data is not exactly in the format you would like to display
+it. For instance, you might be collecting B<bytes> per second, but
+want to display B<bits> per second. This is what the B<L<data
+calculation|rrdgraph_data/CDEF>> command is designed for. After
+B<consolidating> the data, a copy is made and this copy is modified
+using a rather powerful B<L<RPN|rrdgraph_rpn/>> command set.
+
+When you are done fetching and processing the data, it is time to
+graph it (or print it).  This ends the B<rrdtool graph> sequence.
+
+=head1 OPTIONS
+
+=over 4
+
+=item filename
+
+The name and path of the graph to generate. It is recommended to
+end this in C<.png>, C<.svg> or C<.eps>, but B<RRDtool> does not enforce this.
+
+I<filename> can be 'C<->' to send the image to C<stdout>. In
+this case, no other output is generated.
+
+=item Time range
+
+[B<-s>|B<--start> I<time>]
+[B<-e>|B<--end> I<time>]
+[B<-S>|B<--step> I<seconds>]
+
+The start and end of the time series you would like to display, and which
+B<RRA> the data should come from.  Defaults are: 1 day ago until
+now, with the best possible resolution. B<Start> and B<end> can
+be specified in several formats, see
+L<AT-STYLE TIME SPECIFICATION|rrdfetch/> and L<rrdgraph_examples>.
+By default, B<rrdtool graph> calculates the width of one pixel in
+the time domain and tries to get data from an B<RRA> with that
+resolution.  With the B<step> option you can alter this behaviour.
+If you want B<rrdtool graph> to get data at a one-hour resolution
+from the B<RRD>, set B<step> to 3'600. Note: a step smaller than
+one pixel will silently be ignored.
+
+=item Labels
+
+[B<-t>|B<--title> I<string>]
+[B<-v>|B<--vertical-label> I<string>]
+
+A horizontal string at the top of the graph and/or a vertically
+placed string at the left hand side of the graph.
+
+=item Size
+
+[B<-w>|B<--width> I<pixels>]
+[B<-h>|B<--height> I<pixels>]
+[B<-j>|B<--only-graph>]
+
+The width and height of the B<canvas> (the part of the graph with
+the actual data and such). This defaults to 400 pixels by 100 pixels.
+
+If you specify the B<--only-graph> option and set the height E<lt> 32
+pixels you will get a tiny graph image (thumbnail) to use as an icon
+for use in an overview, for example. All labeling will be stripped off
+the graph.
+
+=item Limits
+
+[B<-u>|B<--upper-limit> I<value>]
+[B<-l>|B<--lower-limit> I<value>]
+[B<-r>|B<--rigid>]
+
+By default the graph will be autoscaling so that it will adjust the
+y-axis to the range of the data. You can change this behaviour by
+explicitly setting the limits. The displayed y-axis will then range at
+least from B<lower-limit> to B<upper-limit>. Autoscaling will still
+permit those boundaries to be stretched unless the B<rigid> option is
+set.
+
+[B<-A>|B<--alt-autoscale>]
+
+Sometimes the default algorithm for selecting the y-axis scale is not
+satisfactory. Normally the scale is selected from a predefined
+set of ranges and this fails miserably when you need to graph something
+like C<260 + 0.001 * sin(x)>. This option calculates the minimum and
+maximum y-axis from the actual minimum and maximum data values. Our example
+would display slightly less than C<260-0.001> to slightly more than
+C<260+0.001> (this feature was contributed by Sasha Mikheev).
+
+[B<-J>|B<--alt-autoscale-min>]
+
+Where C<--alt-autoscale> will modify both the absolute maximum AND minimum
+values, this option will only affect the minimum value. The maximum
+value, if not defined on the command line, will be 0. This option can
+be useful when graphing router traffic when the WAN line uses compression,
+and thus the throughput may be higher than the WAN line speed.
+
+[B<-M>|B<--alt-autoscale-max>]
+
+Where C<--alt-autoscale> will modify both the absolute maximum AND minimum
+values, this option will only affect the maximum value. The minimum
+value, if not defined on the command line, will be 0. This option can
+be useful when graphing router traffic when the WAN line uses compression,
+and thus the throughput may be higher than the WAN line speed.
+
+[B<-N>|B<--no-gridfit>]
+
+In order to avoid anti-aliasing effects gridlines are placed on
+integer pixel values. This is by default done by extending
+the scale so that gridlines happens to be spaced using an
+integer number of pixels and also start on an integer pixel value.
+This might extend the scale too much for some logarithmic scales
+and for linear scales where B<--alt-autoscale> is needed.
+Using B<--no-gridfit> disables modification of the scale.
+
+=item Grid
+
+=over 4
+
+=item X-Axis
+
+[B<-x>|B<--x-grid> I<GTM>B<:>I<GST>B<:>I<MTM>B<:>I<MST>B<:>I<LTM>B<:>I<LST>B<:>I<LPR>B<:>I<LFM>]
+
+[B<-x>|B<--x-grid> B<none>]
+
+The x-axis label is quite complex to configure. If you don't have
+very special needs it is probably best to rely on the autoconfiguration
+to get this right. You can specify the string C<none> to suppress the grid
+and labels altogether.
+
+The grid is defined by specifying a certain amount of time in the I<?TM>
+positions. You can choose from C<SECOND>, C<MINUTE>, C<HOUR>, C<DAY>,
+C<WEEK>, C<MONTH> or C<YEAR>. Then you define how many of these should
+pass between each line or label.  This pair (I<?TM:?ST>) needs to be
+specified for the base grid (I<G??>), the major grid (I<M??>) and the
+labels (I<L??>). For the labels you also must define a precision
+in I<LPR> and a I<strftime> format string in I<LFM>.  I<LPR> defines
+where each label will be placed. If it is zero, the label will be
+placed right under the corresponding line (useful for hours, dates
+etcetera).  If you specify a number of seconds here the label is
+centered on this interval (useful for Monday, January etcetera).
+
+ --x-grid MINUTE:10:HOUR:1:HOUR:4:0:%X
+
+This places grid lines every 10 minutes, major grid lines every hour,
+and labels every 4 hours. The labels are placed under the major grid
+lines as they specify exactly that time.
+
+ --x-grid HOUR:8:DAY:1:DAY:1:0:%A
+
+This places grid lines every 8 hours, major grid lines and labels
+each day. The labels are placed exactly between two major grid lines
+as they specify the complete day and not just midnight.
+
+=item Y-Axis
+
+[B<-y>|B<--y-grid> I<grid step>B<:>I<label factor>]
+
+[B<-y>|B<--y-grid> B<none>]
+
+Y-axis grid lines appear at each I<grid step> interval.  Labels are
+placed every I<label factor> lines.  You can specify C<-y none> to
+suppress the grid and labels altogether.  The default for this option is
+to automatically select sensible values.
+
+If you have set --y-grid to 'none' not only the labels get supressed, also
+the space reserved for the labels is removed. You can still add space
+manually if you use the --units-length command to explicitly reserve space.
+
+[B<-Y>|B<--alt-y-grid>]
+
+Place the Y grid dynamically based on the graph's Y range. The algorithm
+ensures that you always have a grid, that there are enough but not too many
+grid lines, and that the grid is metric. That is the grid lines are placed
+every 1, 2, 5 or 10 units. This parameter will also ensure that you get
+enough decimals displayed even if your graph goes from 69.998 to 70.001. 
+(contributed by Sasha Mikheev).
+
+[B<-o>|B<--logarithmic>]
+
+Logarithmic y-axis scaling.
+
+[B<-X>|B<--units-exponent> I<value>]
+
+This sets the 10**exponent scaling of the y-axis values. Normally,
+values will be scaled to the appropriate units (k, M, etc.).  However,
+you may wish to display units always in k (Kilo, 10e3) even if the data
+is in the M (Mega, 10e6) range, for instance. Value should be an
+integer which is a multiple of 3 between -18 and 18 inclusively.  It is
+the exponent on the units you wish to use. For example, use 3 to
+display the y-axis values in k (Kilo, 10e3, thousands), use -6 to
+display the y-axis values in u (Micro, 10e-6, millionths).  Use a value
+of 0 to prevent any scaling of the y-axis values.
+
+This option is very effective at confusing the heck out of the default
+rrdtool autoscaler and grid painter. If rrdtool detects that it is not
+successful in labeling the graph under the given circumstances, it will switch
+to the more robust B<--alt-y-grid> mode.
+
+[B<-L>|B<--units-length> I<value>]
+
+How many digits should rrdtool assume the y-axis labels to be? You
+may have to use this option to make enough space once you start
+fideling with the y-axis labeling.
+
+[B<--units=si>]
+
+With this option y-axis values on logarithmic graphs will be scaled to 
+the appropriate units (k, M, etc.) instead of using exponential notation.
+Note that for linear graphs, SI notation is used by default.
+
+=back
+
+=item Miscellaneous
+
+[B<-z>|B<--lazy>]
+
+Only generate the graph if the current graph is out of date or not
+existent.
+
+[B<-f>|B<--imginfo> I<printfstr>]
+
+After the image has been created, the graph function uses printf
+together with this format string to create output similar to the PRINT
+function, only that the printf function is supplied with the parameters
+I<filename>, I<xsize> and I<ysize>. In order to generate an B<IMG> tag
+suitable for including the graph into a web page, the command line
+would look like this:
+
+ --imginfo '<IMG SRC="/img/%s" WIDTH="%lu" HEIGHT="%lu" ALT="Demo">'
+
+[B<-c>|B<--color> I<COLORTAG>#I<rrggbb>[I<aa>]]
+
+Override the default colors for the standard elements of the graph. The
+I<COLORTAG> is one of C<BACK> background, C<CANVAS> for the background of
+the actual graph, C<SHADEA> for the left and top border, C<SHADEB> for the
+right and bottom border, C<GRID>, C<MGRID> for the major grid, C<FONT> for
+the color of the font, C<AXIS> for the axis of the graph, C<FRAME> for the
+line around the color spots and finally C<ARROW> for the arrow head pointing
+up and forward. Each color is composed out of three hexadecimal numbers
+specifying its rgb color component (00 is off, FF is maximum) of red, green
+and blue. Optionally you may add another hexadecimal number specifying the
+transparency (FF is solid). You may set this option several times to alter
+multiple defaults.
+
+A green arrow is made by: C<--color ARROW#00FF00>
+
+[B<--zoom> I<factor>]
+
+Zoom the graphics by the given amount. The factor must be E<gt> 0
+
+[B<-n>|B<--font> I<FONTTAG>B<:>I<size>B<:>[I<font>]]
+
+This lets you customize which font to use for the various text
+elements on the RRD graphs. C<DEFAULT> sets the default value for all
+elements, C<TITLE> for the title, C<AXIS> for the axis labels, C<UNIT>
+for the vertical unit label, C<LEGEND> for the graph legend.
+
+Use Times for the title: C<--font TITLE:13:/usr/lib/fonts/times.ttf>
+
+If you do not give a font string you can modify just the sice of the default font:
+C<--font TITLE:13:>.
+
+If you specify the size 0 then you can modify just the font without touching
+the size. This is especially usefull for altering the default font without
+resetting the default fontsizes: C<--font DEFAULT:0:/usr/lib/fonts/times.ttf>.
+
+RRDtool comes with a preset default font. You can set the environment
+variable C<RRD_DEFAULT_FONT> if you want to change this.
+
+Truetype fonts are only supported for PNG output. See below.
+
+[B<-R>|B<--font-render-mode> {I<normal>,I<light>,I<mono>}]
+
+This lets you customize the strength of the font smoothing,
+or disable it entirely using I<mono>. By default, I<normal>
+font smoothing is used.
+
+[B<-B>|B<--font-smoothing-threshold> I<size>]
+
+This specifies the largest font size which will be rendered
+bitmapped, that is, without any font smoothing. By default,
+no text is rendered bitmapped.
+
+[B<-E>|B<--slope-mode>]
+
+RRDtool graphs are composed of stair case curves by default. This is in line with
+the way RRDtool calculates its data. Some people favor a more 'organic' look
+for their graphs even though it is not all that true.
+
+[B<-a>|B<--imgformat> B<PNG>|B<SVG>|B<EPS>|B<PDF>]
+
+Image format for the generated graph. For the vector formats you can
+choose among the standard Postscript fonts Courier-Bold,
+Courier-BoldOblique, Courier-Oblique, Courier, Helvetica-Bold,
+Helvetica-BoldOblique, Helvetica-Oblique, Helvetica, Symbol,
+Times-Bold, Times-BoldItalic, Times-Italic, Times-Roman, and ZapfDingbats.
+
+[B<-i>|B<--interlaced>]
+
+If images are interlaced they become visible on browsers more quickly.
+
+[B<-g>|B<--no-legend>]
+
+Suppress generation of the legend; only render the graph.
+
+[B<-F>|B<--force-rules-legend>]
+
+Force the generation of HRULE and VRULE legends even if those HRULE or
+VRULE will not be drawn because out of graph boundaries (mimics
+behaviour of pre 1.0.42 versions).
+
+[B<-T>|B<--tabwidth> I<value>]
+
+By default the tab-width is 40 pixels, use this option to change it.
+
+[B<-b>|B<--base> I<value>]
+
+If you are graphing memory (and NOT network traffic) this switch
+should be set to 1024 so that one Kb is 1024 byte. For traffic
+measurement, 1 kb/s is 1000 b/s.
+
+[B<-W>|B<--watermark> I<string>]
+
+Adds the given string as a watermark, horizontally centred, at the bottom 
+of the graph.
+
+=item Data and variables
+
+B<DEF:>I<vname>B<=>I<rrdfile>B<:>I<ds-name>B<:>I<CF>[B<:step=>I<step>][B<:start=>I<time>][B<:end=>I<time>]
+
+B<CDEF:>I<vname>B<=>I<RPN expression>
+
+B<VDEF:>I<vname>B<=>I<RPN expression>
+
+You need at least one B<DEF> statement to generate anything. The
+other statements are useful but optional.
+See L<rrdgraph_data> and L<rrdgraph_rpn> for the exact format.
+
+=item Graph and print elements
+
+You need at least one graph element to generate an image and/or
+at least one print statement to generate a report.
+See L<rrdgraph_graph> for the exact format.
+
+=back
+
+=head1 SEE ALSO
+
+L<rrdgraph> gives an overview of how B<rrdtool graph> works.
+L<rrdgraph_data> describes B<DEF>,B<CDEF> and B<VDEF> in detail.
+L<rrdgraph_rpn> describes the B<RPN> language used in the B<?DEF> statements.
+L<rrdgraph_graph> page describes all of the graph and print functions.
+
+Make sure to read L<rrdgraph_examples> for tipsE<amp>tricks.
+
+=head1 AUTHOR
+
+Program by Tobias Oetiker E<lt>tobi@oetiker.chE<gt>
+
+This manual page by Alex van den Bogaerdt E<lt>alex@ergens.op.het.netE<gt>
+
diff --git a/doc/rrdgraph.src b/doc/rrdgraph.src
deleted file mode 100644 (file)
index b829a7b..0000000
+++ /dev/null
@@ -1,370 +0,0 @@
-=include name
-
-=head1 SYNOPSIS
-
-B<rrdtool graph> I<filename>
-[E<lt>B<L<option|rrdgraph/OPTIONS>>E<gt> ...]
-E<lt>B<L<data definition|rrdgraph_data/DEF>>E<gt>[ ...]
-[E<lt>B<L<data calculation|rrdgraph_data/CDEF>>E<gt> ...]
-[E<lt>B<L<variable definition|rrdgraph_data/VDEF>>E<gt> ...]
-[E<lt>B<L<graph element|rrdgraph_graph/GRAPH>>E<gt> ...]
-[E<lt>B<L<print element|rrdgraph_graph/PRINT>>E<gt> ...]
-
-=head1 DESCRIPTION
-
-The B<graph> function of B<RRDtool> is used to present the
-data from an B<RRD> to a human viewer.  Its main purpose is to
-create a nice graphical representation but it can also generate
-a numerical report.
-
-=head1 OVERVIEW
-
-B<rrdtool graph> needs data to work with, use one or more
-B<L<data definition|rrdgraph_data/DEF>> statements to collect this
-data.  You are not limited to one database, it's perfectly legal to
-collect data from two or more databases (one per statement though).
-
-If you want to display averages, maxima, percentiles etcetera
-it is best to collect them now using the
-B<L<variable definition|rrdgraph_data/VDEF>> statement.  At this
-stage, this command works at the unprocessed data from the B<RRD>.
-I<(Note: this is not yet true; it works on consolidated information
-right now)>
-
-The data fetched from the B<RRA> is then B<consolidated> so that
-there is exactly one datapoint per pixel in the graph. If you do
-not take care yourself, B<RRDtool> will expand the range slightly
-if necessary (in that case the first pixel may very well become
-unknown!).
-
-Sometimes data is not exactly as you would like to display it. For
-instance, you might be collecting B<bytes> per second but want to
-display B<bits> per second. This is where the
-B<L<data calculation|rrdgraph_data/CDEF>> command is designed for.
-After B<consolidating> the data, a copy is made and this copy is
-modified using a rather flexible B<L<RPN|rrdgraph_rpn/>> command
-set.  If you use B<L<variable definition|rrdgraph_data/VDEF>>
-statements after this, they work on the consolidated data and may
-return other values for maximum, minimum etcetera!
-
-When you are done fetching and processing the data, it is time to
-graph it (or print it).  This ends the B<rrdtool graph> sequence.
-
-=head1 OPTIONS
-
-It is expected that most options will move to the graph definition
-statements (after all, most of them do define graph elements...).
-
-=over 4
-
-=item filename
-
-The name and path of the graph to generate. It is recommended to
-end this in C<.png>, C<.svg> or C<.eps> but B<RRDtool> does not enforce this.
-
-I<filename> can be 'C<->' to send the image to C<stdout>. In
-that case, no other output is generated.  
-
-Z<>
-
-=item Time range
-
-B<[-s|--start E<lt>timeE<gt>]>
-B<[-e|--end E<lt>timeE<gt>]>
-B<[-S|--step E<lt>secondsE<gt>]>
-
-The start and end of what you would like to display, and which
-B<RRA> the data should come from.  Defaults are: 1 day ago until
-now, with the best possible resolution. B<Start> and B<end> can 
-be specified in several formats, see
-L<AT-STYLE TIME SPECIFICATION|rrdfetch/> and L<rrdgraph_examples>.
-By default, B<rrdtool graph> calculates the width of one pixel in
-the time domain and tries to get data from an B<RRA> with that
-resolution.  With the B<step> option you can alter this behaviour.
-If you want B<rrdtool graph> to get data at a one-hour resolution
-from the B<RRD>, set B<step> to 3600.  Note: a step smaller than
-one pixel will silently be ignored.
-
-Z<>
-
-=item Labels
-
-B<[-t|--title E<lt>stringE<gt>]>
-B<[-v|--vertical-label E<lt>stringE<gt>]>
-
-A horizontal string at the top of the graph and/or a vertically
-placed string at the left hand side of the graph. I<New: (not
-yet implemented)> The string can contain formatter options that
-are used to include variables (from B<VDEF>s) and newlines.
-
-Z<>
-
-=item Size
-
-B<[-w|--width E<lt>pixelsE<gt>]>
-B<[-h|--height E<lt>pixelsE<gt>]>
-B<[-j|--only-graph]>
-
-The width and height of the B<canvas> (the part of the graph with
-the actual lines and such). Defaults are 400 pixels by 100 pixels.
-
-If you specify the B<--only-graph> and set the height < 32 pixels you will
-get a tiny graph image to use as an icon in a potential overview. All
-labeling will be stripped off the graph.
-
-Z<>
-
-=item Limits
-
-I<Old behaviour, until the new options are implemented>
-B<[-u|--upper-limit E<lt>valueE<gt>]>
-B<[-l|--lower-limit E<lt>valueE<gt>]>
-B<[-r|--rigid]>
-
-By default the graph will be autoscaling so that it displays the
-portion of the y-axis that is actually used. You can change this
-behaviour by setting the limits.  The displayed y-axis will show
-at least from B<lower-limit> to B<upper-limit>.  Autoscaling will
-still permit those boundaries to be stretched unless the B<rigid>
-option is set.
-
-I<New behaviour, after the new options are implemented>
-B<[--maximum-upper-limit E<lt>valueE<gt>]>
-B<[--minimum-upper-limit E<lt>valueE<gt>]>
-B<[--maximum-lower-limit E<lt>valueE<gt>]>
-B<[--minimum-lower-limit E<lt>valueE<gt>]>
-
-By default the graph will be autoscaling so that it displays the
-portion of the y-axis that is actually used. You can change this
-behaviour by setting the limits.  The displayed y-axis will show
-at most B<maximum-upper-limit> and at least B<minimum-upper-limit>
-at the top, and similarly at least B<maximum-lower-limit> and
-at most B<minimum-lower-limit> at the bottom.  The default is to
-display at most B<infinity> (so: no limit) and at least
-B<negative infinity> (no minimal value) at the top. The bottom of
-the graph has similar defaults. Note that the minimum lower limit
-is the lowest one so you should compare this with maximum upper
-limit when you try to figure out what you should set.
-
-To make sure the graph shows the range of I<-1000> to I<2000>,
-optionally expanding to no more than I<-3000> to I<4000>,
-set the following options:
-
---maximum-upper-limit 4000 --minimum-upper-limit 2000
---maximum-lower-limit -1000 --minimum-lower-limit -3000
-
-To mimic the old B<rigid> option, you can do:
-
---maximum-upper-limit 4000 --minimum-upper-limit 4000
---maximum-lower-limit -3000 --minimum-lower-limit -3000
-
-B<[-A|--alt-autoscale]>
-
-Sometimes the default algorithm for selecting the y-axis scale is not
-performing very well.  Normally the scale is selected from a predefined
-set of ranges and this fails miserably when you need to graph something
-like C<260 + 0.001 * sin(x)>. This option calculates the minimum and
-maximum y-axis from the actual minimum and maximum values. Our example
-would display slightly less than C<260-0.001> to slightly more than
-C<260+0.001> (Contributed by Sasha Mikheev).
-
-B<[-M|--alt-autoscale-max]>
-
-Where C<--alt-autoscale> will modify both the absolute maximum AND minimum
-values, this option will only affect the maximum value. The minimum
-value, if not defined on the command line, will be 0. This option can
-be useful when graphing router traffic when the WAN line uses compression,
-and thus the throughput may be higher than the WAN line speed.
-
-B<[-N|--no-gridfit]>
-
-To avoid anti-aliasing effects gridlines are placed on 
-integer pixel values. This is by default done by extending 
-the scale so gridlines happens to be spaced using an 
-integer number of pixels, and starts on integer pixel value.
-This might extend the scale too much for some logarithmic scales
-and for linear scales where --alt-autoscale is needed.
-Using --no-gridfit disables modification of the scale,
-and just truncates y-coordinates to integer values for bitmap
-formats.
-
-Z<>
-
-=item Grid
-
-=over 4
-
-=item X-Axis
-
-B<[-x|--x-grid E<lt>I<GTMC<:>GSTC<:>MTMC<:>MSTC<:>LTMC<:>LSTC<:>LPRC<:>LFM>E<gt>]>
-
-B<[-x|--x-grid C<none>]>
-
-The x-axis label is quite complex to configure, if you don't have
-very special needs it is probably best to rely on the autoconfiguration
-to get this right.  You can specify the string C<none> to skip the grid
-and labels altogether.
-
-The grid is defined by specifying a certain amount of time in the I<?TM>
-positions. You can choose from C<SECOND>, C<MINUTE>, C<HOUR>, C<DAY>,
-C<WEEK>, C<MONTH> or C<YEAR>. Then you define how many of these should
-pass between each line or label.  This pair (I<?TM:?ST>) needs to be
-specified for the base grid (I<G??>), the major grid (I<M??>) and the
-labels (I<L??>). For the labels you also need to define a precision
-in I<LPR> and a I<strftime> format string in I<LFM>.  I<LPR> defines
-where each label will be placed. If it is zero, the label will be
-placed right under the corresponding line (useful for hours, dates
-etcetera).  If you specify a number of seconds here the label is
-centered in this interval (useful for Monday, January etcetera).
-
-Example: C<--x-grid MINUTE:10:HOUR:1:HOUR:4:0:%X>
-
-This places grid lines every 10 minutes, major grid lines every hour
-and labels every 4 hours. The labels are placed under the major grid
-lines as they specify exactly that time.
-
-Example: C<--x-grid HOUR:8:DAY:1:DAY:1:0:%A>
-
-This places grid lines every 8 hours, major grid lines and labels
-each day. The labels are placed exactly between two major grid lines
-as they specify the complete day and not just midnight.
-
-Z<>
-
-=item Y-Axis
-
-B<[-y|--y-grid I<E<lt>grid stepE<gt>:E<lt>label factorE<gt>>]>
-
-B<[-y|--y-grid C<none>]>
-
-Y-axis grid lines appear at each I<grid step> interval.  Labels are
-placed every I<label factor> lines.  You can specify C<-y none> to
-skip the grid and labels altogether.  The default for this option is
-to automatically select sensible values.
-
-B<[-Y|--alt-y-grid]>
-
-Place Y grid dynamically based on graph Y range. Algorithm ensures
-that you always have grid, that there are enough but not too many
-grid lines and the grid is metric. That is grid lines are placed
-every 1, 2, 5 or 10 units.  (contributed by Sasha Mikheev)
-
-B<[-o|--logarithmic]>
-
-Logarithmic y-axis scaling.
-
-B<[-X|--units-exponent E<lt>valueE<gt>]>
-
-This sets the 10**exponent scaling of the y-axis values.  Normally
-values will be scaled to the appropriate units (k, M, etc.).  However
-you may wish to display units always in k (Kilo, 10e3) even if the data
-is in the M (Mega, 10e6) range for instance.  Value should be an
-integer which is a multiple of 3 between -18 and 18 inclusive.  It is
-the exponent on the units you which to use.  For example, use 3 to
-display the y-axis values in k (Kilo, 10e3, thousands), use -6 to
-display the y-axis values in u (Micro, 10e-6, millionths).  Use a value
-of 0 to prevent any scaling of the y-axis values.
-
-Z<>
-
-=back
-
-Z<>
-
-=item Miscellaneous
-
-B<[-z|--lazy]>
-
-Only generate the graph, if the current graph is out of date or not
-existent.
-
-B<[-f|--imginfo E<lt>printfstrE<gt>]>
-
-After the image has been created, the graph function uses printf
-together with this format string to create output similar to the PRINT
-function, only that the printf is supplied with the parameters
-I<filename>, I<xsize> and I<ysize>. In order to generate an B<IMG> tag
-suitable for including the graph into a web page, the command line
-would look like this:
-
-    --imginfo '<IMG SRC="/img/%s" WIDTH="%lu" HEIGHT="%lu" ALT="Demo">'
-
-B<[-c|--color I<COLORTAG>#I<rrggbb>[I<aa>]]>
-
-Override the default colors for the standard elements of the graph. The
-I<COLORTAG> is one of C<BACK> background, C<CANVAS> for the background of
-the actual graph, C<SHADEA> for the left and top border, C<SHADEB> for the
-right and bottom border, C<GRID>, C<MGRID> for the major grid, C<FONT> for
-the color of the font, C<AXIS> for the axis of the graph and finaly C<ARROW>
-for the arrow head pointing to the future. Each color is composed out of
-three hexadecimal numbers specifying its color component (00 is off, FF is
-maximum) of red, green and blue. Optionally you may add another hexadecimal
-number specifying the transparency (FF is solid). You may set this option
-several times to alter multiple defaults.
-
-A green arrow is made by: C<--color ARROW:00FF00>
-
-B<[--zoom I<factor>]>
-
-Zoom the graphics by the given amount ... The factor must be E<gt> 0
-
-B<[-n|--font I<FONTTAG>B<:>I<size>B<:>I<font>]>
-
-Lets you customize which font to use for the various text elements on the
-RRD graphs. C<DEFAULT> sets the default value for all elements C<TITLE>,
-C<AXIS> for the axis labels, C<UNIT> for the vertical unit label, C<LEGEND>
-for the graph legend.
-
-Use Times for the title: C<--font TITLE:13:/usr/lib/fonts/times.ttf>
-
-B<[-a|--imgformat C<PNG>|C<SVG>|C<EPS>|C<PDF>]>
-
-Image format for the generated graph.
-
-B<[-i|--interlaced]>
-
-If images are interlaced they become visible on browsers more quickly.
-
-B<[-g|--no-legend]>
-
-Suppress generation of legend; only render the graph.
-
-B<[-F|--force-rules-legend]>
-
-Force the generation of HRULE and VRULE legend even if those HRULE or VRULE will not be drawn because out of graph boundaries (mimics behaviour of pre 1.0.42 versions).
-
-B<[-T|--tabwidth E<lt>valueE<gt>]>
-
-By default the tab-width is 40 pixels, use this option to change it.
-
-B<[-b|--base E<lt>valueE<gt>]>
-
-If you are graphing memory (and NOT network traffic) this switch
-should be set to 1024 so that one Kb is 1024 byte. For traffic
-measurement, 1 kb/s is 1000 b/s.
-
-Z<>
-
-=item Data and variables
-
-B<DEF:>I<E<lt>vnameE<gt>>=I<E<lt>rrdfileE<gt>>:I<E<lt>ds-nameE<gt>>:I<E<lt>CFE<gt>>[:step=I<E<lt>stepE<gt>>][:start=I<E<lt>timeE<gt>>][:end=I<E<lt>timeE<gt>>]
-
-B<CDEF:>I<E<lt>vnameE<gt>>=I<E<lt>RPN expressionE<gt>>
-
-B<VDEF:>I<E<lt>vnameE<gt>>=I<E<lt>RPN expressionE<gt>>
-
-You need at least one B<DEF> statement to generate anything. The
-other statements are useful but optional.
-See L<rrdgraph_data> and L<rrdgraph_rpn> for exact format.
-
-Z<>
-
-=item Graph and print elements
-
-You need at least one graph element to generate an image and/or
-at least one print statement to generate a report.
-See L<rrdgraph_graph> for exact format.
-
-=back
-
-=include see_also
diff --git a/doc/rrdgraph_data.pod b/doc/rrdgraph_data.pod
new file mode 100644 (file)
index 0000000..6c8b28a
--- /dev/null
@@ -0,0 +1,106 @@
+=head1 NAME
+
+rrdgraph_data - preparing data for graphing in rrdtool graph
+
+=head1 SYNOPSIS
+
+B<DEF:>I<E<lt>vnameE<gt>>=I<E<lt>rrdfileE<gt>>:I<E<lt>ds-nameE<gt>>:I<E<lt>CFE<gt>>[:step=I<E<lt>stepE<gt>>][:start=I<E<lt>timeE<gt>>][:end=I<E<lt>timeE<gt>>][:reduce=I<E<lt>B<CF>E<gt>>]
+
+B<VDEF>:I<vname>=I<RPN expression>
+
+B<CDEF>:I<vname>=I<RPN expression>
+
+=head1 DESCRIPTION
+
+These three instructions extract data values out of the B<RRD> files,
+optionally altering them (think, for example, of a bytes to bits
+conversion). If so desired, you can also define variables containing
+useful information such as maximum, minimum etcetera. Two of the
+instructions use a language called B<RPN> which is described in its
+own manual page.
+
+Variable names (I<vname>) must be made up strings of the following characters
+C<A-Z, a-z, 0-9, -,_> and a maximum length of 255 characters.
+
+When picking variable names, make sure you do not choose a name that is
+already taken by an RPN operator. A save bet it to use lowercase or
+mixedcase names for variables since operators will always be in uppercase.
+
+=head1 DEF
+
+B<DEF:>I<E<lt>vnameE<gt>>=I<E<lt>rrdfileE<gt>>:I<E<lt>ds-nameE<gt>>:I<E<lt>CFE<gt>>[:step=I<E<lt>stepE<gt>>][:start=I<E<lt>timeE<gt>>][:end=I<E<lt>timeE<gt>>][:reduce=I<E<lt>B<CF>E<gt>>]
+
+This command fetches data from an B<RRD> file.  The virtual name
+I<vname> can then be used throughout the rest of the script. By
+default, an B<RRA> which contains the correct consolidated data
+at an appropriate resolution will be chosen.  The resolution can
+be overridden with the L<--step|rrdgraph/item_Time> option.
+The resolution can again be overridden by specifying the B<step size>.
+The time span of this data is the same as for the graph by default,
+you can override this by specifying B<start and end>.  Remember to
+escape colons in the time specification!
+
+If the resolution of the data is higher than the resolution of the
+graph, the data will be further consolidated. This may result in
+a graph that spans slightly more time than requested.
+Ideally each point in the graph should correspond with one B<CDP>
+from an B<RRA>.  For instance, if your B<RRD> has an B<RRA> with
+a resolution of 1800 seconds per B<CDP>, you should create an
+image with width 400 and time span 400*1800 seconds (use appropriate
+start and end times, such as C<--start end-8days8hours>).
+
+If consolidation needs to be done, the B<CF> of the B<RRA> specified in the
+B<DEF> itself will be used to reduce the data density. This behaviour can
+be changed using C<:reduce=I<E<lt>B<CF>E<gt>>>.  This optional parameter
+specifies the B<CF> to use during the data reduction phase.
+
+Example:
+
+        DEF:ds0=router.rrd:ds0:AVERAGE
+        DEF:ds0weekly=router.rrd:ds0:AVERAGE:step=7200
+        DEF:ds0weekly=router.rrd:ds0:AVERAGE:start=end-1h
+        DEF:ds0weekly=router.rrd:ds0:AVERAGE:start=11\:00:end=start+1h
+
+=head1 VDEF
+
+B<VDEF>:I<vname>=I<RPN expression>
+
+This command returns a value and/or a time according to the B<RPN>
+statements used. The resulting I<vname> will, depending on the
+functions used, have a value and a time component.  When you use
+this I<vname> in another B<RPN> expression, you are effectively
+inserting its value just as if you had put a number at that place.
+The variable can also be used in the various graph and print
+elements.
+
+Example: C<VDEF:avg=mydata,AVERAGE>
+
+Note that currently only agregation functions work in VDEF rpn expressions.
+Patches to change this are welcome.
+
+=head1 CDEF
+
+B<CDEF>:I<vname>=I<RPN expression>
+
+This command creates a new set of data points (in memory only, not
+in the B<RRD> file) out of one or more other data series. The B<RPN>
+instructions are used to evaluate a mathematical function on each
+data point. The resulting I<vname> can then be used further on in
+the script, just as if it were generated by a B<DEF> instruction.
+
+Example: C<CDEF:mydatabits=mydata,8,*>
+
+=head1 SEE ALSO
+
+L<rrdgraph> gives an overview of how B<rrdtool graph> works.
+L<rrdgraph_data> describes B<DEF>,B<CDEF> and B<VDEF> in detail.
+L<rrdgraph_rpn> describes the B<RPN> language used in the B<?DEF> statements.
+L<rrdgraph_graph> page describes all of the graph and print functions.
+
+Make sure to read L<rrdgraph_examples> for tipsE<amp>tricks.
+
+=head1 AUTHOR
+
+Program by Tobias Oetiker E<lt>tobi@oetiker.chE<gt>
+
+This manual page by Alex van den Bogaerdt E<lt>alex@ergens.op.het.netE<gt>
diff --git a/doc/rrdgraph_data.src b/doc/rrdgraph_data.src
deleted file mode 100644 (file)
index 1f8fcb7..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-=include name
-
-=head1 SYNOPSIS
-
-B<DEF:>I<E<lt>vnameE<gt>>=I<E<lt>rrdfileE<gt>>:I<E<lt>ds-nameE<gt>>:I<E<lt>CFE<gt>>[:step=I<E<lt>stepE<gt>>][:start=I<E<lt>timeE<gt>>][:end=I<E<lt>timeE<gt>>][:reduce=I<E<lt>B<CF>E<gt>>]
-
-B<VDEF>:I<vname>=I<RPN expression>
-
-B<CDEF>:I<vname>=I<RPN expression>
-
-=head1 DESCRIPTION
-
-These three instructions collect the data out of the B<RRD> files,
-optionally altering it (think of a bytes to bits conversion) and
-if desired you can define variables containing useful information
-such as maximum, minimum etcetera. Two of the instructions use
-a language called B<RPN> which is described in its own manual page.
-
-=head1 DEF
-
-B<DEF:>I<E<lt>vnameE<gt>>=I<E<lt>rrdfileE<gt>>:I<E<lt>ds-nameE<gt>>:I<E<lt>CFE<gt>>[:step=I<E<lt>stepE<gt>>][:start=I<E<lt>timeE<gt>>][:end=I<E<lt>timeE<gt>>][:reduce=I<E<lt>B<CF>E<gt>>]
-
-This command fetches data from an B<RRD> file.  The virtual name
-I<vname> can then be used throughout the rest of the script. By
-default, an B<RRA> which contains the correct consolidated data
-at an appropriate resolution will be chosen.  The resolution can
-be overridden with the L<--step|rrdgraph/item_Time> option. 
-The resolution can again be overridden by specifying the B<step size>.
-The time span of this data is the same as for the graph by default,
-you can override this by specifying B<start and end>.  Remember to
-escape colons in the time specification!
-
-If the resolution of the data is higher than the resolution of off
-graph, the data will be further consolidated.  This may result in
-a graph that spans slightly more time than requested.
-Ideally each point in the graph should correspond with one B<CDP>
-from an B<RRA>.  For instance, if your B<RRD> has an B<RRA> with
-a resolution of 1800 seconds per B<CDP>, you should create an
-image with width 400 and time span 400*1800 seconds (use appropriate
-start and end times, such as C<--start end-8days8hours>).
-
-If consolidation needs to be done, the B<CF> of the B<RRA> specified in the
-B<DEF> itself will be used to reduce the data density.  This behaviour can
-be changed using C<:reduce=I<E<lt>B<CF>E<gt>>>.  This optional parameter
-specifies the B<CF> to use during the data reduction phase.
-
-Example:
-
-        DEF:ds0=router.rrd:ds0:AVERAGE
-        DEF:ds0weekly=router.rrd:ds0:AVERAGE:step=7200
-        DEF:ds0weekly=router.rrd:ds0:AVERAGE:start=end-1h
-        DEF:ds0weekly=router.rrd:ds0:AVERAGE:start=11\:00:end=start+1h
-
-=head1 VDEF
-
-B<VDEF>:I<vname>=I<RPN expression>
-
-This command returns a value and/or a time according to the B<RPN>
-statements used. The resulting I<vname> will, depending on the
-functions used, have a value and a time component.  When you use
-this I<vname> in another B<RPN> expression, you are effectively
-inserting its value just as if you had put a number at that place.
-The variable can also be used in the various graph and print
-elements. I<Not yet implemented:> [ Everywhere you can insert a
-number, you can also use the B<VDEF> (provided that it is set of course) ]
-
-Example: C<VDEF:avg=mydata,AVERAGE>
-
-=head1 CDEF
-
-B<CDEF>:I<vname>=I<RPN expression>
-
-This command creates a new set of data points (in memory only, not
-in the B<RRD> file) out of one or more other data series. The B<RPN>
-instructions are used to evaluate a mathematical function on each
-data point. The resulting I<vname> can then be used further on in
-the script, just as if it were generated by a B<DEF> instruction.
-
-Example: C<CDEF:mydatabits=mydata,8,*>
-
-=include see_also
diff --git a/doc/rrdgraph_examples.pod b/doc/rrdgraph_examples.pod
new file mode 100644 (file)
index 0000000..64e3840
--- /dev/null
@@ -0,0 +1,137 @@
+=head1 NAME
+
+rrdgraph_examples - Examples for rrdtool graph
+
+=head1 SYNOPSIS
+
+B<rrdtool graph /home/httpd/html/test.png --img-format PNG>
+
+followed by any of the examples below
+
+=head1 DESCRIPTION
+
+For your convenience some of the commands are explained here
+by using detailed examples. They are not always cut-and-paste
+ready because comments are intermixed with the examples.
+
+=head1 EXAMPLES
+
+=head2 Data with multiple resolutions
+
+    --end now --start end-120000s --width 400
+    DEF:ds0a=/home/rrdtool/data/router1.rrd:ds0:AVERAGE
+    DEF:ds0b=/home/rrdtool/data/router1.rrd:ds0:AVERAGE:step=1800
+    DEF:ds0c=/home/rrdtool/data/router1.rrd:ds0:AVERAGE:step=7200
+    LINE1:ds0a#0000FF:"default resolution\l"
+    LINE1:ds0b#00CCFF:"resolution 1800 seconds per interval\l"
+    LINE1:ds0c#FF00FF:"resolution 7200 seconds per interval\l"
+
+=head2 Nicely formatted legend section
+
+    DEF:ds0=/home/rrdtool/data/router1.rrd:ds0:AVERAGE
+    DEF:ds1=/home/rrdtool/data/router1.rrd:ds1:AVERAGE
+    VDEF:ds0max=ds0,MAXIMUM
+    VDEF:ds0avg=ds0,AVERAGE
+    VDEF:ds0min=ds0,MINIMUM
+    VDEF:ds0pct=ds0,95,PERCENT
+    VDEF:ds1max=ds1,MAXIMUM
+    VDEF:ds1avg=ds1,AVERAGE
+    VDEF:ds1min=ds1,MINIMUM
+    VDEF:ds1pct=ds1,95,PERCENT
+
+Note: consolidation occurs here.
+
+    CDEF:ds0bits=ds0,8,*
+    CDEF:ds1bits=ds1,8,*
+
+Note: 10 spaces to move text to the right
+
+    COMMENT:"          "
+
+Note: the column titles have to be as wide as the columns
+
+    COMMENT:"Maximum    "
+    COMMENT:"Average    "
+    COMMENT:"Minimum    "
+
+    COMMENT:"95th percentile\l"
+    AREA:ds0bits#00C000:"Inbound "
+    GPRINT:ds0max:"%6.2lf %Sbps"
+    GPRINT:ds0avg:"%6.2lf %Sbps"
+    GPRINT:ds0min:"%6.2lf %Sbps"
+    GPRINT:ds0pct:"%6.2lf %Sbps\l"
+    LINE1:ds1bits#0000FF:"Outbound"
+    GPRINT:ds1max:"%6.2lf %Sbps"
+    GPRINT:ds1avg:"%6.2lf %Sbps"
+    GPRINT:ds1min:"%6.2lf %Sbps"
+    GPRINT:ds1pct:"%6.2lf %Sbps\l"
+
+=head2 Offsetting a line on the y-axis
+
+Depending on your needs you can do this in two ways:
+
+=over 4
+
+=item *
+
+Offset the data, then graph this
+
+    DEF:mydata=my.rrd:ds:AVERAGE
+
+Note: this will also influence any other command that uses "data"
+
+    CDEF:data=mydata,100,+
+    LINE1:data#FF0000:"Data with offset"
+
+=item *
+
+Graph the original data, with an offset
+
+    DEF:mydata=my.rrd:ds:AVERAGE
+
+Note: no color in the first line so it is not visible
+
+    LINE1:100
+
+Note: the second line gets stacked on top of the first one
+
+    LINE1:data#FF0000:"Data with offset":STACK
+
+=back
+
+=head2 Time ranges
+
+    Last four weeks: --start end-4w --end 00:00
+    January 2001:    --start 20010101 --end start+31d
+    January 2001:    --start 20010101 --end 20010201
+    Last hour:       --start end-1h
+    Last 24 hours:   <nothing at all>
+    Yesterday:       --end 00:00
+
+=head2 Viewing the current and previous week together
+
+    --end now --start end-1w
+    DEF:thisweek=router.rrd:ds0:AVERAGE
+    DEF:lastweek=router.rrd:ds0:AVERAGE:end=now-1w:start=end-1w
+
+Shift the data forward by one week (604800 seconds)
+
+    SHIFT:lastweek:604800
+    [ more of the usual VDEF and CDEF stuff if you like ]
+    AREA:lastweek#0000FF:Last\ week
+    LINE1:thisweek#FF0000:This\ week
+
+=head1 SEE ALSO
+
+L<rrdgraph> gives an overview of how B<rrdtool graph> works.
+L<rrdgraph_data> describes B<DEF>,B<CDEF> and B<VDEF> in detail.
+L<rrdgraph_rpn> describes the B<RPN> language used in the B<xDEF> statements.
+L<rrdgraph_graph> page describes all the graph and print functions.
+
+Make sure to read L<rrdgraph_examples> for tipsE<amp>tricks.
+
+=head1 AUTHOR
+
+Program by Tobias Oetiker E<lt>tobi@oetiker.chE<gt>
+
+This manual page by Alex van den Bogaerdt E<lt>alex@ergens.op.het.netE<gt>
diff --git a/doc/rrdgraph_examples.src b/doc/rrdgraph_examples.src
deleted file mode 100644 (file)
index a597ece..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-=include name
-
-=head1 SYNOPSIS
-
-B<rrdtool graph /home/httpd/html/test.png --img-format PNG \>
-
-followed by any of the examples below
-
-=head1 DESCRIPTION
-
-For your convenience some of the commands are explained here
-by using detailed examples. They are not always cut-and-paste
-ready because comments are intermixed with the examples.
-
-=head1 EXAMPLES
-
-=head2 Data with multiple resolutions
-
-    --end now --start end-120000s --width 400
-    DEF:ds0a=/home/rrdtool/data/router1.rrd:ds0:AVERAGE
-    DEF:ds0b=/home/rrdtool/data/router1.rrd:ds0:AVERAGE:step=1800
-    DEF:ds0c=/home/rrdtool/data/router1.rrd:ds0:AVERAGE:step=7200
-    LINE1:ds0a#0000FF:"default resolution\n"
-    LINE1:ds0b#00CCFF:"resolution 1800 seconds per interval\n"
-    LINE1:ds0c#FF00FF:"resolution 7200 seconds per interval\n"
-
-=head2 Nicely formatted legend section
-
-    DEF:ds0=/home/rrdtool/data/router1.rrd:ds0:AVERAGE
-    DEF:ds1=/home/rrdtool/data/router1.rrd:ds1:AVERAGE
-    VDEF:ds0max=ds0,MAXIMUM,8,*
-    VDEF:ds0avg=ds0,AVERAGE,8,*
-    VDEF:ds0min=ds0,MINIMUM,8,*
-    VDEF:ds0pct=95,ds0,PERCENTILE,8,*
-    VDEF:ds1max=ds1,MAXIMUM,8,*
-    VDEF:ds1avg=ds1,AVERAGE,8,*
-    VDEF:ds1min=ds1,MINIMUM,8,*
-    VDEF:ds1pct=95,ds1,PERCENTILE,8,*
-Note: consolidation occurs here.
-    CDEF:ds0bits=ds0,8,*
-    CDEF:ds1bits=ds1,8,*
-Note: 10 spaces to move text to the right
-    COMMENT:"          "
-Note: three times size == 11 chars, "###.## xBps"
-    COMMENT:"Maximum    "
-    COMMENT:"Average    "
-    COMMENT:"Minimum    "
-Note: last line contains new-line character
-    COMMENT:"95th percentile\n"
-    AREA:ds0bits#00C000:"Inbound "
-    GPRINT:ds0max:"%6.2lf %Sbps"
-    GPRINT:ds0avg:"%6.2lf %Sbps"
-    GPRINT:ds0min:"%6.2lf %Sbps"
-    GPRINT:ds0pct:"%6.2lf %Sbps\n"
-    LINE1:ds1bits#0000FF:"Outbound"
-    GPRINT:ds1max:"%6.2lf %Sbps"
-    GPRINT:ds1avg:"%6.2lf %Sbps"
-    GPRINT:ds1min:"%6.2lf %Sbps"
-    GPRINT:ds1pct:"%6.2lf %Sbps\n"
-
-=head2 Offsetting a line on the y-axis
-
-Depending on your needs you can do this in two ways:
-
-=over 4
-
-=item *
-
-Offset the data, then graph this
-
-    DEF:mydata=my.rrd:ds:AVERAGE
-Note: this will also influence anything that uses "data"
-    CDEF:data=mydata,100,+
-    LINE1:data#FF0000:"Data with offset"
-
-=item *
-
-Graph the original data, with an offset
-
-    DEF:mydata=my.rrd:ds:AVERAGE
-Note: no color in the first line so it is not visible
-    LINE1:100
-Note: the second line gets stacked on top of the first one
-    LINE1:data#FF0000:"Data with offset":STACK
-
-=back
-
-=head2 Time ranges
-
-    Last four weeks: --start end-4w --end 00:00
-    Januari 2001:    --start 200101010000 --end start+31d
-    Januari 2001:    --start 200101010000 --end 200102010000
-    Last hour:       --start end-1h
-    Last 24 hours:   <nothing at all>
-    Yesterday:       --end 00:00
-
-=head2 Viewing Januari+Februari 2000 and 2001 together
-
-Define a graph area of 31+29 days (!) spanning Jan. and Feb.
-    --start 20000101 --end 20000301
-    DEF:jan2000=router.rrd:ds0:AVERAGE:start 20000101 end start+31d
-    DEF:jan2001=router.rrd:ds0:AVERAGE:start 20010101 end start+31d
-Note: mind the extra day in 2000 ...
-    DEF:feb2000=router.rrd:ds0:AVERAGE:start 20000201 end start+29d
-Note: 29 feb 2001 is *unknown*
-    DEF:feb2001=router.rrd:ds0:AVERAGE:start 20010201 end start+28d
-    VDEF:offset=jan2001,FIRST,jan2000,FIRST,-,-1,*
-    [ more of the usual VDEF and CDEF stuff if you like ]
-    LINE1:jan2000#00003F:"Januari 2000"
-    [ gprint stuff ]
-    LINE1:feb2001#003F00:"Februari 2000"
-    [ gprint stuff ]
-Note: offset is made negative by the VDEF statement
-    SHIFT:offset
-    LINE1:jan2001#0000FF:"Januari 2001"
-    [ gprint stuff ]
-    LINE1:feb2001#00FF00:"Februari 2001"
-    [ gprint stuff ]
-
-=include see_also
-
diff --git a/doc/rrdgraph_graph.pod b/doc/rrdgraph_graph.pod
new file mode 100644 (file)
index 0000000..6546ab5
--- /dev/null
@@ -0,0 +1,379 @@
+=pod
+
+=head1 NAME
+
+rrdgraph_graph - rrdtool graph command reference
+
+=head1 SYNOPSIS
+
+B<PRINT>B<:>I<vname>B<:>I<format>
+
+B<GPRINT>B<:>I<vname>B<:>I<format>
+
+B<COMMENT>B<:>I<text>
+
+B<VRULE>B<:>I<time>B<#>I<color>[B<:>I<legend>]
+
+B<HRULE>B<:>I<value>B<#>I<color>[B<:>I<legend>]
+
+B<LINE>[I<width>]B<:>I<value>[B<#>I<color>][B<:>[I<legend>][B<:STACK>]]
+
+B<AREA>B<:>I<value>[B<#>I<color>][B<:>[I<legend>][B<:STACK>]]
+
+B<TICK>B<:>I<vname>B<#>I<rrggbb>[I<aa>][B<:>I<fraction>[B<:>I<legend>]]
+
+B<SHIFT>B<:>I<vname>B<:>I<offset>
+
+=cut
+
+#
+#B<PART>B<:>I<vname>B<#>I<rrggbb>[I<aa>][B<:>I<legend>]
+#
+
+=pod
+
+B<PRINT>B<:>I<vname>B<:>I<CF>B<:>I<format> (deprecated)
+
+B<GPRINT>B<:>I<vname>B<:>I<CF>B<:>I<format> (deprecated)
+
+
+B<STACK>B<:>I<vname>B<#>I<color>[B<:>I<legend>] (deprecated)
+
+=head1 DESCRIPTION
+
+These instructions allow you to generate your image or report.
+If you don't use any graph elements, no graph is generated.
+Similarly, no report is generated if you don't use print options.
+
+=head1 PRINT
+
+=over 4
+
+
+=item B<PRINT:>I<vname>B<:>I<format>[B<:strftime>]
+
+Depending on the context, either the value component or the time
+component of a B<VDEF> is printed using I<format>. It is an error
+to specify a I<vname> generated by a B<DEF> or B<CDEF>.
+
+Any text in I<format> is printed literally with one exception:
+The percent character introduces a formatter string. This string
+can be:
+
+For printing values:
+
+=over 4
+
+=item B<%%>
+
+just prints a literal '%' character
+
+=item B<%#.#le>
+
+prints numbers like 1.2346e+04. The optional integers # denote field
+width and decimal precision.
+
+=item B<%#.#lf>
+
+prints numbers like 12345.6789, with optional field width
+and precision.
+
+=item B<%s>
+
+place this after B<%le>, B<%lf> or B<%lg>. This will be replaced by the
+appropriate SI magnitude unit and the value will be scaled
+accordingly (123456 -> 123.456 k).
+
+=item B<%S>
+
+is similar to B<%s>. It does, however, use a previously defined
+magnitude unit. If there is no such unit yet, it tries to define
+one (just like B<%s>) unless the value is zero, in which case the magnitude
+unit stays undefined. Thus, formatter strings using B<%S> and no B<%s>
+will all use the same magnitude unit except for zero values.
+
+=back
+
+If you PRINT a VDEF value, you can also print the time associated with it by appending the string
+B<:strftime> to the format. Note that rrdtool uses the strftime function of your OSs clibrary. This means that
+the conversion specifier may vary. Check the manual page if you are uncertain. The following is a list of
+conversion specifiers usually supported across the board. 
+
+=over 4
+
+=item B<%a>
+
+The abbreviated weekday name according to the current locale.
+
+=item B<%A>
+
+The full weekday name according to the current locale.
+
+=item B<%b>
+
+The abbreviated month name according to the current locale.
+
+=item B<%B>
+
+The full month name according to the current locale.
+
+=item B<%c>
+
+The preferred date and time representation for the current locale.
+
+=item B<%d>
+
+The day of the month as a decimal number (range 01 to 31).
+
+=item B<%H>
+
+The hour as a decimal number using a 24-hour clock (range 00 to 23).
+
+=item B<%I>
+
+The hour as a decimal number using a 12-hour clock (range 01 to 12).
+
+=item B<%j>
+
+The day of the year as a decimal number (range 001 to 366).
+
+=item B<%m>
+
+The month as a decimal number (range 01 to 12).
+
+=item B<%M>
+
+The minute as a decimal number (range 00 to 59).
+
+=item B<%p>
+
+Either `AM' or `PM' according to the given time value, or the corresponding
+strings for the current locale.  Noon is treated as `pm' and midnight as
+`am'.  Note that in many locales and `pm' notation is unsupported and in
+such cases %p will return an empty string.
+
+=item B<%S>
+
+The second as a decimal number (range 00 to 61).
+
+=item B<%U>
+
+The  week  number  of  the current year as a decimal number, range 00 to 53, starting with the
+first Sunday as the first day of week 01. See also %V and %W.
+
+=item B<%V>
+
+The ISO 8601:1988 week number of the current year as a decimal number, range 01 to  53,  where
+week  1 is the first week that has at least 4 days in the current year, and with Monday as the
+first day of the week. See also %U and %W.
+
+=item B<%w>
+
+The day of the week as a decimal, range 0 to 6, Sunday being 0.  See also %u.
+
+=item B<%W>
+
+The week number of the current year as a decimal number, range 00 to  53,  starting  with  the
+first Monday as the first day of week 01.
+
+=item B<%x>
+
+The preferred date representation for the current locale without the time.
+
+=item B<%X>
+
+The preferred time representation for the current locale without the date.
+
+=item B<%y>
+
+The year as a decimal number without a century (range 00 to 99).
+
+=item B<%Y>
+
+The year as a decimal number including the century.
+
+=item B<%Z>
+
+The time zone or name or abbreviation.
+
+=item B<%%>
+
+A literal `%' character.
+
+=back
+
+=item B<PRINT:>I<vname>B<:>I<CF>B<:>I<format>
+
+I<Deprecated. Use the new form of this command in new scripts.>
+The first form of this command is to be used with B<CDEF> I<vname>s.
+
+=back
+
+=head1 GRAPH
+
+=over 4
+
+=item B<GPRINT>B<:>I<vname>B<:>I<format>
+
+This is the same as C<PRINT>, but printed inside the graph.
+
+=item B<GPRINT>B<:>I<vname>B<:>I<CF>B<:>I<format>
+
+I<Deprecated. Use the new form of this command in new scripts.>
+This is the same as C<PRINT>, but printed inside the graph.
+
+=item B<COMMENT>B<:>I<text>
+
+Text is printed literally in the legend section of the graph. Note that in
+RRDtool 1.2 you have to escape colons in COMMENT text in the same way you
+have to escape them in B<*PRINT> commands by writing B<'\:'>.
+
+=item B<VRULE>B<:>I<time>B<#>I<color> [B<:>I<legend> ]
+
+Draw a vertical line at I<time>.  Its color is composed from three
+hexadecimal numbers specifying the rgb color components (00 is off, FF is
+maximum) red, green and blue followed by an optional alpha. Optionally, a legend box and string is
+printed in the legend section. I<time> may be a number or a variable
+from a B<VDEF>. It is an error to use I<vname>s from B<DEF> or B<CDEF> here.
+
+=item B<HRULE>B<:>I<value>B<#>I<color> [ :I<legend> ]
+
+Draw a horyzontal line at I<value>.  HRULE acts much like LINE except that
+will have no effect on the scale of the graph. If a HRULE is outside the
+graphing area it will just not be visible.
+
+=item B<LINE>[I<width>]B<:>I<value>[B<#>I<color>][B<:>[I<legend>][B<:STACK>]]
+
+Draw a line of the specified width onto the graph. I<width> can be a
+floating point number. If the color is not specified, the drawing is done
+'invisibly'. This is useful when stacking something else on top of this
+line. Also optional is the legend box and string which will be printed in
+the legend section if specified. The B<value> can be generated by B<DEF>,
+B<VDEF>, and B<CDEF>.  If the optional B<STACK> modifier is used, this line
+is stacked on top of the previous element which can be a B<LINE> or an
+B<AREA>.
+
+When you do not specify a color, you cannot specify a legend.  Should
+you want to use STACK, use the "LINEx:<value>::STACK" form.
+
+=item B<AREA>B<:>I<value>[B<#>I<color>][B<:>[I<legend>][B<:STACK>]]
+
+See B<LINE>, however the area between the x-axis and the line will
+be filled.
+
+=item B<TICK>B<:>I<vname>B<#>I<rrggbb>[I<aa>][B<:>I<fraction>[B<:>I<legend>]]
+
+Plot a tick mark (a vertical line) for each value of I<vname> that is
+non-zero and not *UNKNOWN*. The I<fraction> argument specifies the length of
+the tick mark as a fraction of the y-axis; the default value is 0.1 (10% of
+the axis). Note that the color specification is not optional. The TICK marks normaly
+start at the lower edge of the graphing area. If the fraction is negative they start
+at the upper border of the graphing area.
+
+=item B<SHIFT>B<:>I<vname>B<:>I<offset>
+
+Using this command B<RRDtool> will graph the following elements
+with the specified offset.  For instance, you can specify an
+offset of S<( 7*24*60*60 = ) 604'800 seconds> to "look back" one
+week. Make sure to tell the viewer of your graph you did this ...
+As with the other graphing elements, you can specify a number or
+a variable here.
+
+=cut
+
+# This section describes the curruently defunct
+# PieChart code.
+#
+# =item B<PART>B<:>I<vname>B<#>I<rrggbb>[I<aa>][B<:>I<legend>]
+#
+# B<RRDtool> has now support for B<pie charts>. If you include the
+# B<PART> command, the canvas is extended to make room for a chart.
+# The size of the canvas is determined by the lesser of
+# L<width and height|rrdgraph/item_Size>.
+#
+# Pie parts will be concatenated, the first one will start at the
+# top and parts will be created clockwise.  The size of the part
+# is defined by the value part of the L<VDEF|rrdgraph_data/VDEF>
+# function.  It should return a number between 0 and 100, being a
+# percentage.  Providing wrong input will produce undefined results.
+#
+#
+
+=pod
+
+=item B<STACK>B<:>I<vname>B<#>I<color>[B<:>I<legend>]
+
+I<Deprecated.  Use the B<STACK> modifiers on the other commands.>
+
+=back
+
+B<Some notes on stacking>
+
+When stacking, an element is not placed above the X-axis but rather
+on top of the previous element.  There must be something to stack
+upon.
+
+You can use an B<invisible> LINE or AREA to stacked upon.
+
+An B<unknown> value makes the entire stack unknown from that moment on.
+You don't know where to begin (the unknown value) and therefore do
+not know where to end.
+
+If you want to make sure you will be displaying a certain variable,
+make sure never to stack upon the unknown value.  Use a CDEF instruction
+with B<IF> and B<UN> to do so.
+
+=head1 NOTES on legend arguments
+
+=head2 Escaping the colon
+
+A colon ':' in a I<legend> argument will mark the end of the
+legend. To enter a ':' as part of a legend, the colon must be escaped
+with a backslash '\:'.  Beware that many environments process
+backslashes themselves, so it may be necessary to write two
+backslashes in order to one being passed onto rrd_graph.
+
+=head2 String Formatting
+
+The text printed below the actual graph can be formatted by appending special
+escape characters at the end of a text. When ever such a character occurs,
+all pending text is pushed onto the graph according to the character
+specified.
+
+Valid markers are: B<\j> for justified, B<\l> for left aligned, B<\r> for
+right aligned, and B<\c> for centered. In the next section there is an
+example showing how to use centered formatting.
+
+B<\n> is a valid alias for B<\l> since incomplete parsing in earlier
+versions of rrdtool lead to this behaviour and a number of people has been using it.
+
+Normally there are two space characters inserted between every two items
+printed into the graph. The space following a string can be suppressed by
+putting a B<\g> at the end of the string. The B<\g> also ignores any space
+inside the string if it is at the very end of the string. This can be used
+in connection with B<%s> to suppress empty unit strings.
+
+ GPRINT:a:MAX:%lf%s\g
+
+A special case is COMMENT:B<\s> which inserts some additional vertical space
+before placing the next row of legends.
+
+If you are using the proportional font in your graph, you can use tab
+characters or the sequence B<\t> to line-up legend elements. Note that
+the tabs inserted are relative to the start of the current legend
+element!
+
+=head1 SEE ALSO
+
+L<rrdgraph> gives an overview of how B<rrdtool graph> works.
+L<rrdgraph_data> describes B<DEF>,B<CDEF> and B<VDEF> in detail.
+L<rrdgraph_rpn> describes the B<RPN> language used in the B<?DEF> statements.
+L<rrdgraph_graph> page describes all of the graph and print functions.
+
+Make sure to read L<rrdgraph_examples> for tipsE<amp>tricks.
+
+=head1 AUTHOR
+
+Program by Tobias Oetiker E<lt>tobi@oetiker.chE<gt>
+
+This manual page by Alex van den Bogaerdt E<lt>alex@ergens.op.het.netE<gt>
diff --git a/doc/rrdgraph_graph.src b/doc/rrdgraph_graph.src
deleted file mode 100644 (file)
index 4d4a557..0000000
+++ /dev/null
@@ -1,296 +0,0 @@
-=include name
-
-=head1 SYNOPSIS
-
-=over 4
-
-=item B<to be deprecated commands>
-
-=over 4
-
-=item B<PRINT> : I<vname> : I<CF> : I<format>
-
-=item B<GPRINT> : I<vname> : I<CF> : I<format>
-
-=item B<HRULE> : I<value> # I<color> [ :I<legend> ]
-
-=item B<STACK> : I<vname> # I<color> [ :I<legend> ]
-
-=back
-
-=item B<available commands>
-
-=over 8
-
-=item B<PRINT> : I<vname> : I<format>
-
-=item B<GPRINT> : I<vname> : I<format>
-
-=item B<COMMENT> : I<text>
-
-=item B<VRULE> : I<vname> # I<color> [ : I<legend> ]
-
-=item B<LINE>{I<width>} : I<vname> # I<color> [ : I<legend> ] [ : STACK ]
-
-=item B<AREA> C<:> I<vname> C<#> I<color> [ C<:> I<legend> ] [ C<:> C<STACK> ]
-
-=cut
-
-# =item B<PART> : I<vname> B<#> I<rrggbbaa> [ B<:> I<legend> ]
-
-=pod
-
-=item B<TICK> : I<vname> B<#> I<rrggbbaa> [ : I<fraction> [ : I<legend> ] ]
-
-=item B<SHIFT> : I<vname> , I<offset>
-
-=back
-
-=back
-
-=head1 DESCRIPTION
-
-These instructions allow you to generate your image or report.
-If you don't use any graph elements, no graph is generated.
-Similarly no report is generated if you don't use print options.
-
-=head1 PRINT
-
-=over 4
-
-=item B<PRINT> : I<vname> : I<CF> : I<format>
-
-I<Deprecated. Use the new form of this command in new scripts.>
-The first form of this command is to be used with B<CDEF> I<vname>s.
-
-=item B<PRINT> : I<vname> : I<format>
-
-Depending on the context, either the value component or the time
-component of a B<VDEF> is printed using I<format>. It is an error
-to specify a I<vname> generated by a B<DEF> or B<CDEF>.
-
-Any text in I<format> is printed literally with one exception:
-The percent character introduces a formatter string. This string
-can be:
-
-For printing values:
-
-=over 4
-
-=item *
-
-B<%%> just prints a literal '%' character
-
-=item *
-
-B<%#.#le> prints like 1.2346e+04. Optional numbers # are field width and
-decimal precision
-
-=item *
-
-B<%#.#lf> prints like 12345.6789, with optional field width and precision
-
-=item *
-
-B<%s> place this after B<%le>, B<%lf> or B<%lg>. This will be replaced by the
-appropriate SI magnitude unit and the value will be scaled
-accordingly (123456 -> 123.456 k)
-
-=item *
-
-B<%S> is similar to B<%s>. It does however use a previously defined
-magnitude unit. If there is no such unit yet, it tries to define
-one (just like B<%s>). However, if the value is zero, the magnitude
-unit stays undefined. Thus, formatter strings using B<%S> and no B<%s>
-will all use the same magnitude unit except for zero values.
-
-=back
-
-For printing times:
-
-=over 4
-
-=item *
-
-B<%%> just prints a literal '%' character
-
-=item *
-
-B<%a, %A> prints abbreviated, full weekday name
-
-=item *
-
-B<%b, %B> prints abbreviated, full month name
-
-=item *
-
-B<%d, %m, %y, %H, %M, %S> day,month,year,hour,minute,second all in two-digit format
-
-=item *
-
-B<%Y> year in 4-digit format
-
-=item *
-
-B<%I, %p>  hour (01..12), 'am' or 'pm'
-
-=item *
-
-B<%j, %w> day of the week (0..6), day of the year (1..366)
-
-=item *
-
-B<%c, %x, %X> date+time, date, time
-
-=item *
-
-B<%U, %W> week number of the current year with either the first Sunday or
-the first Monday determining the first week
-
-=item *
-
-B<%Z> time zone
-
-=back
-
-=back
-
-=head1 GRAPH
-
-=over 4
-
-=item B<GPRINT> : I<vname> : I<CF> : I<format>
-
-I<Deprecated. Use the new form of this command in new scripts.>
-This is the same as C<PRINT> but now it is printed inside the graph.
-
-=item B<GPRINT> : I<vname> : I<format>
-
-This is the same as C<PRINT> but now it is printed inside the graph.
-
-=item B<COMMENT> : I<text>
-
-Text is printed literally in the legend section of the graph
-
-=item B<HRULE> : I<value> # I<color> [ :I<legend> ]
-
-Draw an horizontal line at I<value>. Its color is composed from three
-hexadecimal numbers specifying the color components (00 is off, FF is
-maximum) red, green and blue.  Optionally a legend box and string is
-printed in the legend section. I<value> can be a variable from a B<VDEF>.
-It is an error to use I<vname>s from B<DEF> or B<CDEF> here.
-
-=item B<VRULE> : I<vname> # I<color> [ : I<legend> ]
-
-Draw a vertical line at I<time>.  Its color is composed from three
-hexadecimal numbers specifying the color components (00 is off, FF is
-maximum) red, green and blue.  Optionally a legend box and string is
-printed in the legend section. I<time> may be a number or a variable
-from a B<VDEF>. It is an error to use I<vname>s from B<DEF> or B<CDEF> here.
-
-=item B<LINE>{I<width>} : I<vname> # I<color> [ : I<legend> ] [ : STACK ]
-
-Draw a line of the specified width into the graph. If the color
-is not specified, the drawing is done 'blind'.  This is useful when
-stacking something else on top of this line. Also optional is the
-legend box and string which will be printed in the legend section
-if specified. The B<vname> can be generated by B<DEF>, B<VDEF> and
-B<CDEF>.  If the optional B<STACK> modifier is used, this line is
-stacked on top of the previous element which can be a B<LINEx> or
-an B<AREA>
-
-=item B<AREA> C<:> I<vname> C<#> I<color> [ C<:> I<legend> ] [ C<:> C<STACK> ]
-
-See B<LINE>, however the area between the x-axis and the line will
-also be filled.
-
-=item B<STACK> : I<vname> # I<color> [ :I<legend> ]
-
-I<Deprecated.  Use the B<STACK> modifiers on the other commands.>
-I<Note: the comments on stacking are still valid...>
-Repeats the last B<LINEx> or B<AREA> however it doesn't start at the
-x-axis but rather on top of the previous element. This implies that
-there needs to be something to stack on. An invisible B<LINEx> or
-B<AREA> is something you can stack on, an unknown value is not!
-
-Note: When you stack on something that was I<unknown>, the whole
-stack will be I<unknown> for that point in time. If the beginning
-is undefined, there's no way to end somewhere...  If you want to
-graph this stacked variable anyway you need to make sure that the
-B<LINEx> or B<AREA> it gets stacked on is not unknown. Use a CDEF
-instruction with B<IF> and B<UN> to do so.
-
-=cut
-
-#=item B<PART> : I<vname> B<#> I<rrggbbaa> [ B<:> I<legend> ]
-#
-#B<RRDtool> has now support for B<pie charts>. If you include the
-#B<PART> command, the canvas is extended to make room for a chart
-#The size of the canvas is determined by the lesser of
-#L<width and height|rrdgraph/item_Size>.
-#
-#Pie parts will be concatenated, the first one will start at the
-#top and parts will be created clockwise.  The size of the part
-#is defined by the value part of the L<VDEF|rrdgraph_data/VDEF>
-#function.  It should return a number between 0 and 100, being a
-#percentage.  Providing wrong input will produce undefined results.
-
-=pod
-
-=item B<TICK> : I<vname> B<#> I<rrggbbaa> [ : I<fraction> [ : I<legend> ] ]
-
-Plot a tick mark (a vertical line) for each value of I<vname> that is
-non-zero and not *UNKNOWN*. The I<fraction> argument specifies the
-length of the tick mark as a fraction of the y-axis; the default value
-is 0.1 (10% of the axis). Note that the color specification is not
-optional.
-
-=item B<SHIFT> : I<vname> : I<offset>
-
-Using this command B<RRDtool> will graph the following elements
-with the specified offset.  For instance, you can specify an
-offset of S<( 7*24*60*60 = ) 604800 seconds> to "look back" one
-week. Make sure to notify the viewer you did so...
-The offset will be valid until the next B<SHIFT> command, which
-can have an offset of zero to restore normal graphing.
-As with the other graphing elements, you can specify a number or
-a variable here.
-
-=back
-
-=head1 NOTES on legend arguments
-
-=head2 Escaping the colon
-
-In a ':' in a I<legend> argument will mark the end of the legend. To
-enter a ':' into a legend, the colon must be escaped with a backslash '\:'.
-Beware, that many environments look for backslashes themselves, so it may
-be necessary to write two backslashes so that one is passed onto rrd_graph.
-
-=head2 String Formatting
-
-The text printed below the actual graph can be formated by appending special
-escaped characters at the end of a text. When ever such a character occurs,
-all pending text is pushed onto the graph according to the character
-specified.
-
-Valid markers are: B<\j> for justified, B<\l> for left aligned, B<\r> for
-right aligned and B<\c> for centered. In the next section there is an
-example showing how to use centered formating.
-
-Normally there are two space characters inserted between every two items
-printed into the graph. The space following a string can be suppressed by
-putting a B<\g> at the end of the string. The B<\g> also ignores any space
-inside the string if it is at the very end of the string. This can be used
-in connection with B<%s> to suppress empty unit strings.
-
- GPRINT:a:MAX:%lf%s\g
-
-A special case is COMMENT:B<\s> this inserts some additional vertical space
-before placing the next row of legends.
-
-If you are using the proportional font in your graph, you can use tab characters
-or the sequence B<\t> to lin-up legend elements. Note that the tabs inserted are
-relative to the start of the current legend element!
-
-=include see_also
diff --git a/doc/rrdgraph_rpn.pod b/doc/rrdgraph_rpn.pod
new file mode 100644 (file)
index 0000000..b2a84dd
--- /dev/null
@@ -0,0 +1,312 @@
+=head1 NAME
+
+rrdgraph_rpn - About RPN Math in rrdtool graph
+
+=head1 SYNOPSIS
+
+I<RPN expression>:=I<vname>|I<operator>|I<value>[,I<RPN expression>]
+
+=head1 DESCRIPTION
+
+If you have ever used a traditional HP calculator you already know
+B<RPN>. The idea behind B<RPN> is that you have a stack and push
+your data onto this stack. Whenever you execute an operation, it
+takes as many elements from the stack as needed. Pushing is done
+implicitly, so whenever you specify a number or a variable, it gets
+pushed onto the stack automatically.
+
+At the end of the calculation there should be one and only one value left on
+the stack.  This is the outcome of the function and this is what is put into
+the I<vname>.  For B<CDEF> instructions, the stack is processed for each
+data point on the graph. B<VDEF> instructions work on an entire data set in
+one run. Note, that currently B<VDEF> instructions only support a limited
+list of functions.
+
+Example: C<VDEF:maximum=mydata,MAXIMUM>
+
+This will set variable "maximum" which you now can use in the rest
+of your RRD script.
+
+Example: C<CDEF:mydatabits=mydata,8,*>
+
+This means:  push variable I<mydata>, push the number 8, execute
+the operator I<*>. The operator needs two elements and uses those
+to return one value.  This value is then stored in I<mydatabits>.
+As you may have guessed, this instruction means nothing more than
+I<mydatabits = mydata * 8>.  The real power of B<RPN> lies in the
+fact that it is always clear in which order to process the input.
+For expressions like C<a = b + 3 * 5> you need to multiply 3 with
+5 first before you add I<b> to get I<a>. However, with parentheses
+you could change this order: C<a = (b + 3) * 5>. In B<RPN>, you
+would do C<a = b, 3, +, 5, *> without the need for parentheses.
+
+=head1 OPERATORS
+
+=over 4
+
+=item Boolean operators
+
+B<LT, LE, GT, GE, EQ, NE>
+
+Pop two elements from the stack, compare them for the selected condition
+and return 1 for true or 0 for false. Comparing an I<unknown> or an
+I<infinite> value will always result in 0 (false).
+
+B<UN, ISINF>
+
+Pop one element from the stack, compare this to I<unknown> respectively
+to I<positive or negative infinity>. Returns 1 for true or 0 for false.
+
+B<IF>
+
+Pops three elements from the stack.  If the element popped last is 0
+(false), the value popped first is pushed back onto the stack,
+otherwise the value popped second is pushed back. This does, indeed,
+mean that any value other than 0 is considered to be true.
+
+Example: C<A,B,C,IF> should be read as C<if (A) then (B) else (C)>
+
+Z<>
+
+=item Comparing values
+
+B<MIN, MAX>
+
+Pops two elements from the stack and returns the smaller or larger,
+respectively.  Note that I<infinite> is larger than anything else.
+If one of the input numbers is I<unknown> then the result of the operation will be
+I<unknown> too.
+
+B<LIMIT>
+
+Pops two elements from the stack and uses them to define a range.
+Then it pops another element and if it falls inside the range, it
+is pushed back. If not, an I<unknown> is pushed.
+
+The range defined includes the two boundaries (so: a number equal
+to one of the boundaries will be pushed back). If any of the three
+numbers involved is either I<unknown> or I<infinite> this function
+will always return an I<unknown>
+
+Example: C<CDEF:a=alpha,0,100,LIMIT> will return I<unknown> if
+alpha is lower than 0 or if it is higher than 100.
+
+Z<>
+
+=item Arithmetics
+
+B<+, -, *, /, %>
+
+Add, subtract, multiply, divide, modulo
+
+B<SIN, COS, LOG, EXP, SQRT>
+
+Sine and cosine (input in radians), log and exp (natural logarithm),
+square root.
+
+B<ATAN>
+
+Arctangent (output in radians).
+
+B<ATAN2>
+
+Arctangent of y,x components (output in radians).
+This pops one element from the stack, the x (cosine) component, and then
+a second, which is the y (sine) component.
+It then pushes the arctangent of their ratio, resolving the ambiguity between
+quadrants.
+
+Example: C<CDEF:angle=Y,X,ATAN2,RAD2DEG> will convert C<X,Y>
+components into an angle in degrees.
+
+B<FLOOR, CEIL>
+
+Round down or up to the nearest integer.
+
+B<DEG2RAD, RAD2DEG>
+
+Convert angle in degrees to radians, or radians to degrees.
+
+B<ABS>
+
+Take the absolute value.
+
+=item Set Operations
+
+B<SORT, REV>
+
+Pop one element from the stack.  This is the I<count> of items to be sorted
+(or reversed).  The top I<count> of the remaining elements are then sorted
+(or reversed) in place on the stack.
+
+Example: C<CDEF:x=v1,v2,v3,v4,v5,v6,6,SORT,POP,5,REV,POP,+,+,+,4,/> will
+compute the average of the values v1 to v6 after removing the smallest and
+largest.
+
+B<AVG>
+
+Pop one element (I<count>) from the stack. Now pop I<count> elements and build the
+average, ignoring all UNKNOWN values in the process.
+
+Example: C<CDEF:x=a,b,c,d,4,AVG>
+
+B<TREND>
+
+Create a "sliding window" average of another data series.
+
+Usage:
+CDEF:smoothed=x,1800,TREND
+
+This will create a half-hour (1800 second) sliding window average of x.  The
+average is essentially computed as shown here:
+
+                 +---!---!---!---!---!---!---!---!--->
+                                                     now
+                       delay     t0
+                 <--------------->
+                         delay       t1
+                     <--------------->
+                              delay      t2
+                         <--------------->
+
+
+     Value at sample (t0) will be the average between (t0-delay) and (t0)
+     Value at sample (t1) will be the average between (t1-delay) and (t1)
+     Value at sample (t2) will be the average between (t2-delay) and (t2)
+
+=item Special values
+
+B<UNKN>
+
+Pushes an unknown value on the stack
+
+B<INF, NEGINF>
+
+Pushes a positive or negative infinite value on the stack. When
+such a value is graphed, it appears at the top or bottom of the
+graph, no matter what the actual value on the y-axis is.
+
+B<PREV>
+
+Pushes an I<unknown> value if this is the first value of a data
+set or otherwise the result of this B<CDEF> at the previous time
+step. This allows you to do calculations across the data.  This
+function cannot be used in B<VDEF> instructions.
+
+B<PREV(vname)>
+
+Pushes an I<unknown> value if this is the first value of a data
+set or otherwise the result of the vname variable at the previous time
+step. This allows you to do calculations across the data. This
+function cannot be used in B<VDEF> instructions.
+
+B<COUNT>
+
+Pushes the number 1 if this is the first value of the data set, the
+number 2 if it is the second, and so on. This special value allows
+you to make calculations based on the position of the value within
+the data set. This function cannot be used in B<VDEF> instructions.
+
+=item Time
+
+Time inside RRDtool is measured in seconds since the epoch. The
+epoch is defined to be S<C<Thu Jan  1 00:00:00 UTC 1970>>.
+
+B<NOW>
+
+Pushes the current time on the stack.
+
+B<TIME>
+
+Pushes the time the currently processed value was taken at onto the stack.
+
+B<LTIME>
+
+Takes the time as defined by B<TIME>, applies the time zone offset
+valid at that time including daylight saving time if your OS supports
+it, and pushes the result on the stack.  There is an elaborate example
+in the examples section below on how to use this.
+
+=item Processing the stack directly
+
+B<DUP, POP, EXC>
+
+Duplicate the top element, remove the top element, exchange the two
+top elements.
+
+Z<>
+
+=back
+
+=head1 VARIABLES
+
+These operators work only on B<VDEF> statements. Note that currently ONLY these work for B<VDEF>.
+
+=over 4
+
+=item MAXIMUM, MINIMUM, AVERAGE
+
+Return the corresponding value, MAXIMUM and MINIMUM also return
+the first occurrence of that value in the time component.
+
+Example: C<VDEF:avg=mydata,AVERAGE>
+
+=item LAST, FIRST
+
+Return the last/first value including its time.  The time for
+FIRST is actually the start of the corresponding interval, whereas
+LAST returns the end of the corresponding interval.
+
+Example: C<VDEF:first=mydata,FIRST>
+
+=item TOTAL
+
+Returns the rate from each defined time slot multiplied with the
+step size.  This can, for instance, return total bytes transfered
+when you have logged bytes per second. The time component returns
+the number of seconds.
+
+Example: C<VDEF:total=mydata,TOTAL>
+
+=item PERCENT
+
+This should follow a B<DEF> or B<CDEF> I<vname>. The I<vname> is popped,
+another number is popped which is a certain percentage (0..100). The
+data set is then sorted and the value returned is chosen such that
+I<percentage> percent of the values is lower or equal than the result.
+I<Unknown> values are considered lower than any finite number for this
+purpose so if this operator returns an I<unknown> you have quite a lot
+of them in your data.  B<Inf>inite numbers are lesser, or more, than the
+finite numbers and are always more than the I<Unknown> numbers.
+(NaN E<lt> -INF E<lt> finite values E<lt> INF)
+
+Example: C<VDEF:perc95=mydata,95,PERCENT>
+
+=item LSLSLOPE, LSLINT, LSLCORREL
+
+Return the parameters for a B<L>east B<S>quares B<L>ine I<(y = mx +b)> 
+which approximate the provided dataset.  LSLSLOPE is the slope I<(m)> of
+the line related to the COUNT position of the data.  LSLINT is the 
+y-intercept I<(b)>, which happens also to be the first data point on the 
+graph. LSLCORREL is the Correlation Coefficient (also know as Pearson's 
+Product Moment Correlation Coefficient).  It will range from 0 to +/-1 
+and represents the quality of fit for the approximation.   
+
+Example: C<VDEF:slope=mydata,LSLSLOPE>
+
+=back
+
+=head1 SEE ALSO
+
+L<rrdgraph> gives an overview of how B<rrdtool graph> works.
+L<rrdgraph_data> describes B<DEF>,B<CDEF> and B<VDEF> in detail.
+L<rrdgraph_rpn> describes the B<RPN> language used in the B<?DEF> statements.
+L<rrdgraph_graph> page describes all of the graph and print functions.
+
+Make sure to read L<rrdgraph_examples> for tipsE<amp>tricks.
+
+=head1 AUTHOR
+
+Program by Tobias Oetiker E<lt>tobi@oetiker.chE<gt>
+
+This manual page by Alex van den Bogaerdt E<lt>alex@ergens.op.het.netE<gt>
diff --git a/doc/rrdgraph_rpn.src b/doc/rrdgraph_rpn.src
deleted file mode 100644 (file)
index 4aad477..0000000
+++ /dev/null
@@ -1,288 +0,0 @@
-=include name
-
-=head1 SYNOPSIS
-
-I<E<lt>RPN expressionE<gt>> := 
-I<E<lt>vnameE<gt>>|I<E<lt>operatorE<gt>>|I<E<lt>valueE<gt>>
-[ , I<E<lt>RPN expressionE<gt>>]
-
-=head1 DESCRIPTION
-
-If you have ever used a traditional HP calculator you already know
-B<RPN>. The idea behind B<RPN> is that you have a stack and push
-your data onto this stack. Whenever you execute an operation, it
-takes as many elements from the stack as needed. Pushing is done
-implicit so whenever you specify a number or a variable, it gets
-pushed automatically.
-
-At the end of the calculation there should be one and exactly one
-value left on the stack.  This is the outcome of the function and
-this is what is put into the I<vname>.  For B<CDEF> instructions,
-the stack is processed for each data point on the graph. B<VDEF>
-instructions work on an entire data set in one run.
-
-Example: C<CDEF:mydatabits=mydata,8,*>
-
-This means:  push variable I<mydata>, push the number 8, execute
-the operator I<+>. The operator needs two elements and uses those
-to return one value.  This value is then stored in I<mydatabits>.
-As you may have guessed, this instruction means nothing more than
-I<mydatabits = mydata * 8>.  The real power of B<RPN> lies in the
-fact that it is always clear in which order to process the input.
-For expressions like C<a = b + 3 * 5> you need to multiply 3 with
-5 first before you add I<b> to get I<a>. However, with parentheses
-you could change this order: C<a = (b + 3) * 5>. In B<RPN>, you
-would do C<a = b, 3, +, 5, *> and need no parentheses.
-
-=head1 OPERATORS
-
-=over 4
-
-=item Boolean operators
-
-B<LT, LE, GT, GE, EQ, NE>
-
-Pop two elements from the stack, compare them for the selected condition
-and return 1 for true or 0 for false. Comparing an I<unknown> or an
-I<infinite> value will always result in 0 (false).
-
-B<UN, ISINF>
-
-Pop one element from the stack, compare this to I<unknown> respectively
-to I<positive or negative infinity>. Returns 1 for true or 0 for false.
-
-B<IF>
-
-Pops three elements from the stack.  If the last element is 0 (false),
-the first value is pushed back onto the stack, otherwise the second
-popped value is pushed back. This does, indeed, mean that any value
-other than 0 is considered true.
-I<Note: Should this change? It should IMHO as all the other functions
-would return unknown if A,B or C were unknown>
-
-Example: C<A,B,C,IF> should be read as C<if (A) then (B) else (C)>
-
-Z<>
-
-=item Comparing values
-
-B<MIN, MAX> 
-
-Pops two elements from the stack and returns the lesser or larger.
-The two numbers shouldn't be I<infinite> or I<unknown>, if they are
-that value is pushed back onto the stack as the result.
-
-B<LIMIT>
-
-Pops two elements from the stack and uses them to define a range.
-Then it pops another element and if it falls inside the range, it
-is pushed back. If not, an I<unknown> is pushed.
-
-The range defined includes the two boundaries (so: a number equal
-to one of the boundaries will be pushed back). If any of the three
-numbers involved is either I<unknown> or I<infinite> this function
-will always return an I<unknown>
-
-Example: C<CDEF:a=alpha,0,100,LIMIT> will return I<unknown> if
-alpha is lower than 0 or if it is higher than 100.
-
-Z<>
-
-=item Arithmetics
-
-B<+, -, *, /, %>
-
-Add, subtract, multiply, divide, modulo
-
-B<SIN, COS, LOG, EXP, SQRT>
-
-Sine, cosine (input in radians), log, exp (natural logarithm), square root
-
-B<ATAN>
-
-Arctangent. Output in radians.
-
-B<FLOOR, CEIL>
-
-Round down,up to the nearest integer
-
-Z<>
-
-=item Set Operations
-
-B<SORT, REV>
-
-Pop one element from the stack.  This is the I<count> of items to be sorted
-(or reversed).  The top I<count> of the remaining elements are then sorted
-(or reversed) in place on the stack.
-
-Example: C<CDEF:x=v1,v2,v3,v4,v5,v6,6,SORT,POP,5,REV,POP,+,+,+,4,/> will
-compute the average of the values v1..v6 after removing the smallest and
-largest.
-
-B<TREND>
-
-Create a "sliding window" average of another data series.
-
-Usage:
-CDEF:smoothed=x,1800,TREND
-
-This will create a half-hour (1800 second) sliding window average of x.  The
-average is essentially computed as shown here:
-
-                 +---!---!---!---!---!---!---!---!--->
-                                                     now
-                       delay     t0
-                 <--------------->
-                         delay       t1
-                     <--------------->  
-                              delay      t2
-                         <--------------->
-
-
-     Value at sample (t0) will be the average between (t0-delay) and  (t0)
-     Value at sample (t1) will be the average between (t1-delay) and  (t1)
-     Value at sample (t2) will be the average between (t2-delay) and  (t2)
-
-=item Special values
-
-B<UNKN>
-
-Pushes an unknown value on the stack
-
-B<INF, NEGINF>
-
-Pushes a positive or negative infinite value on the stack. When
-such a value is graphed, it appears at the top or bottom of the
-graph, no matter what the actual value on the y-axis is.
-
-B<PREV>
-
-Pushes an I<unknown> value if this is the first value of a data
-set or otherwise the result of this B<CDEF> at the previous time
-step. This allows you to do calculations across the data.  This
-function cannot be used in B<VDEF> instructions.
-
-B<PREV(vname)>
-
-Pushes an I<unknown> value if this is the first value of a data
-set or otherwise the result of vname variable at the previous time
-step. This allows you to do calculations across the data.  This
-function cannot be used in B<VDEF> instructions.
-
-B<COUNT>
-
-Pushes the number 1 if this is the first value of the data set, the 
-number 2 if it is the second, and so on. This special value, allows 
-you to make calculations based on the position of the value within 
-the data set. This function cannot be used in B<VDEF> instructions.
-
-Z<>
-
-=item Time
-
-Time inside RRDtool is measured in seconds since the epoch. This
-epoch is defined to be S<C<Thu Jan  1 00:00:00 UTC 1970>>.
-
-Z<>
-
-=over 4
-
-=item NOW
-
-Pushes the current time on the stack.
-
-Z<>
-
-=item TIME
-
-Pushes the time the currently processed value was taken onto the stack.
-
-Z<>
-
-=item LTIME
-
-Takes the time as defined by B<TIME>, applies the time zone offset
-valid at that time including daylight saving time if your OS supports
-it, and pushes the result on the stack.  There is an elaborate example
-in the examples section on how to use this.
-
-=back
-
-For B<VDEF> operations, B<TIME> and B<LTIME> have a different meaning
-I<not yet implemented>.  As the B<VDEF> statement does not work per
-value but rather on a complete time series, there is no such thing as
-the currently processed value.  However, if you have used an operator
-that returned a time component and would like to have this available
-in the value component in stead (so you can use it as a number), you
-can use B<TIME> or B<LTIME> for that.
-
-Z<>
-
-=item Processing the stack directly
-
-B<DUP, POP, EXC>
-
-Duplicate the top element, remove the top element, exchange the two
-top elements.
-
-Z<>
-
-=item Selecting characteristics
-
-These operators work only on B<VDEF> statements.
-I<We can make most of them work at DEF and CDEF statements. If we do
-so, we have a moving (not rolling!) average, max,min etcetera>
-
-Z<>
-
-=over 4
-
-=item MAXIMUM, MINIMUM, AVERAGE
-
-Return the corresponding value, MAXIMUM and MINIMUM also return
-the first occurrence of that value in the time component.
-
-Example: C<VDEF:avg=mydata,AVERAGE>
-
-Z<>
-
-=item LAST, FIRST
-
-Return the last,first value including its time.  The time for
-FIRST is actually the start of the corresponding interval, where
-the LAST time component returns the end of the corresponding interval.
-
-Example: C<VDEF:first=mydata,FIRST>
-
-Z<>
-
-=item TOTAL
-
-Returns the rate from each defined time slot multiplied with the
-step size.  This can for instance return total bytes transfered
-when you have logged bytes per second. The time component returns
-the amount of seconds 
-
-Example: C<VDEF:total=mydata,TOTAL>
-
-Z<>
-
-=item PERCENT
-
-Should follow a B<DEF> or B<CDEF> I<vname>. This I<vname> is popped,
-another number is popped which is a certain percentage (0..100). The
-data set is then sorted and the value returned is chosen such that
-I<percentage> percent of the values is lower or equal than the result.
-I<Unknown> values are considered lower than any finite number for this
-purpose so if this operator returns an I<unknown> you have quite a lot
-of them in your data.  B<Inf>inite numbers are lesser, or more, than the
-finite numbers and are always more than the I<Unknown> numbers.
-
-Example: C<VDEF:perc95=mydata,95,PERCENT>
-
-=back
-
-=back
-
-=include see_also
index 3558d7a8dc99b6b942b9ef5c24d9c75ad6b199eb..e83d8d6138279af4e4fbd9eb4b38b494357a3e9e 100644 (file)
@@ -1,8 +1,6 @@
 =head1 NAME
 
-rrdtool info - extract header information from an RRD
-
-=for html <div align="right"><a href="rrdinfo.pdf">PDF</a> version.</div>
+rrdinfo - extract header information from an RRD
 
 =head1 SYNOPSIS
 
@@ -22,7 +20,7 @@ This is the output generated by running B<info> on a simple RRD which
 contains two data sources and one RRA. Note that the number after the
 I<last_update> keyword is in seconds since 1970. The string B<NaN>
 stands for I<*UNKNOWN*> data. In the example it means that this RRD
-has neither minimum not maximum values defined for either of its
+has neither minimum nor maximum values defined for either of its
 data sources.
 
  filename = "random.rrd"
@@ -54,11 +52,11 @@ data sources.
 
 =item I<filename.rrd>
 
-The name of the B<RRD> you want to dump.
+The name of the B<RRD> you want to examine.
 
 =back
 
 =head1 AUTHOR
 
-Tobias Oetiker E<lt>oetiker@ee.ethz.chE<gt>
+Tobias Oetiker E<lt>tobi@oetiker.chE<gt>
 
index 20e20daae364a9e4c44572381423c17d4b9cbc6e..a3eb7feedf10289cafa5ee7dfb579200de94dd94 100644 (file)
@@ -1,8 +1,6 @@
 =head1 NAME
 
-rrdtool last - Return the date of the last data sample in an B<RRD>
-
-=for html <div align="right"><a href="rrdlast.pdf">PDF</a> version.</div>
+rrdlast - Return the date of the last data sample in an RRD
 
 =head1 SYNOPSIS
 
@@ -10,8 +8,8 @@ B<rrdtool> B<last> I<filename>
 
 =head1 DESCRIPTION
 
-The B<last> function returns the UNIX timestamp when the RRD was last
-updated.
+The B<last> function returns the UNIX timestamp of the most recent
+update of the RRD.
 
 =over 8
 
diff --git a/doc/rrdlastupdate.pod b/doc/rrdlastupdate.pod
new file mode 100644 (file)
index 0000000..37013cf
--- /dev/null
@@ -0,0 +1,27 @@
+=head1 NAME
+
+rrdlastupdate - Return the most recent update to an RRD
+
+=head1 SYNOPSIS
+
+B<rrdtool> B<lastupdate> I<filename>
+
+=head1 DESCRIPTION
+
+The B<lastupdate> function returns the UNIX timestamp and the 
+value stored for each datum in the most recent update of an RRD.
+
+=over 8
+
+=item I<filename>
+
+The name of the B<RRD> that contains the data.
+
+=back
+
+=head1 AUTHOR
+
+Andy Riebs <andy.riebs@hp.com>
+
+
+
diff --git a/doc/rrdpython.pod b/doc/rrdpython.pod
new file mode 100644 (file)
index 0000000..dc329ec
--- /dev/null
@@ -0,0 +1,59 @@
+=head1 NAME
+
+rrdpython - About the RRD Python bindings
+
+=head1 SYNOPSIS
+
+ import rrdtool
+ rrdtool.create('/tmp/test.rrd', 'DS:foo:GUAGE:20:0:U')
+
+=head1 DESCRIPTION
+
+The B<rrdtool> functions are directly callable via the Python programming
+language. This wrapper implementation has been written from the scratch
+(without  SWIG)
+
+The API's simply expects string parameters to the functions.  Please refer
+to the other B<rrdtool> documentation for functions and valid arguments.
+
+=head1 EXAMPLE
+
+ sys.path.append('/path/to/rrdtool/lib/python2.3/site-packages/')
+ import rrdtool, tempfile
+
+ DAY = 86400
+ YEAR = 365 * DAY
+ fd,path = tempfile.mkstemp('.png')
+
+ rrdtool.graph(path,
+              '--imgformat', 'PNG',
+              '--width', '540',
+              '--height', '100',
+              '--start', "-%i" % YEAR,
+              '--end', "-1",
+              '--vertical-label', 'Downloads/Day',
+              '--title', 'Annual downloads',
+              '--lower-limit', '0',
+              'DEF:downloads=downloads.rrd:downloads:AVERAGE',
+              'AREA:downloads#990033:Downloads')
+
+ info = rrdtool.info('downloads.rrd')
+ print info['last_update']
+ print info['ds']['downloads']['minimal_heartbeat']
+
+If you use the B<site-python-install> make target you can drop to first sys.path.append
+line since the rrdtool module will be available everywhere.
+
+If rrdtool runs into trouble, it will throw an exception which you might want to catch.
+
+=head1 SEE ALSO
+
+rrdcreate, rrdupdate, rrdgraph, rrddump, rrdfetch, rrdtune, rrdlast,
+rrdxport, rrdinfo
+
+=head1 AUTHOR
+
+Hye-Shik Chang E<lt>perky@i18n.orgE<gt>
+
+Alan Milligan E<lt>alan.milligan@last-bastion.netE<gt>
+
index 89b9d776552646b2a47a8210846239db7e661c17..917f3fe14e5b789f88197b83d39b3522e6699ec8 100644 (file)
@@ -1,8 +1,6 @@
 =head1 NAME
 
-rrdtool resize - alters the size of an RRA and creates new .rrd file
-
-=for html <div align="right"><a href="rrdresize.pdf">PDF</a> version.</div>
+rrdresize - alters the size of an RRA and creates a new .rrd file
 
 =head1 SYNOPSIS
 
@@ -15,25 +13,25 @@ an B<RRA>.
 
 =over 8
 
-=item I<filename> 
+=item I<filename>
 
 the name of the B<RRD> you want to alter.
 
-=item I<rra-num> 
+=item I<rra-num>
 
 the B<RRA> you want to alter. You can find the number using B<rrdtool info>.
 
-=item B<GROW> 
+=item B<GROW>
 
 used if you want to add extra rows to an RRA. The extra rows will be inserted
 as the rows that are oldest.
 
-=item B<SHRINK> 
+=item B<SHRINK>
 
 used if you want to remove rows from an RRA. The rows that will be removed
 are the oldest rows.
 
-=item I<rows> 
+=item I<rows>
 
 the number of rows you want to add or remove.
 
@@ -41,12 +39,12 @@ the number of rows you want to add or remove.
 
 =head1 NOTES
 
-The new .rrd file, with the modified RRAs, is written to the file 
-B<resize.rrd> in the current directory.  The original .rrd file is not
-modified.
+The new .rrd file, with the modified RRAs, is written to the file
+B<resize.rrd> in the current directory.  B<The original .rrd file is not
+modified>.
 
 It is possible to abuse this tool and get strange results
-by first removing some rows and then reinsert the same amount (effectively
+by first removing some rows and then reinserting the same amount (effectively
 clearing them to be Unknown). You may thus end up with unknown data in one
 RRA while at the same timestamp this data is available in another RRA.
 
index e587d8446765be10dfc7cde9bb2f364862461382..e098e0dfc1cfa6cb6275a5c72f3748fe2121ca61 100644 (file)
@@ -1,8 +1,6 @@
 =head1 NAME
 
-rrdtool restore - restore the contents of an B<RRD> from its XML dump format
-
-=for html <div align="right"><a href="rrdrestore.pdf">PDF</a> version.</div>
+rrdrestore - Restore the contents of an RRD from its XML dump format
 
 =head1 SYNOPSIS
 
@@ -12,13 +10,13 @@ S<[B<--range-check>|B<-r>]>
 =head1 DESCRIPTION
 
 The B<restore> function reads the XML representation of an RRD and converts
-it into the native B<RRD> format.
+it to the native B<RRD> format.
 
 =over 8
 
 =item I<filename.xml>
 
-The name of the B<XML> you want to restore.
+The name of the B<XML> file you want to restore.
 
 =item I<filename.rrd>
 
@@ -27,7 +25,7 @@ The name of the B<RRD> to restore.
 =item B<--range-check>|B<-r>
 
 Make sure the values in the RRAs do not exceed the limits defined for
-the different data sources.
+the various data sources.
 
 =item B<--force-overwrite>|B<-f>
 
@@ -37,4 +35,4 @@ Allows B<RRDtool> to overwrite the destination B<RRD>.
 
 =head1 AUTHOR
 
-Tobias Oetiker <oetiker@ee.ethz.ch>
+Tobias Oetiker <tobi@oetiker.ch>
diff --git a/doc/rrdruby.pod b/doc/rrdruby.pod
new file mode 100644 (file)
index 0000000..9633447
--- /dev/null
@@ -0,0 +1,86 @@
+=head1 NAME
+
+rrdruby - About the RRD Ruby bindings
+
+=head1 SYNOPSIS
+
+ require "RRD"
+ RRD.create(
+    rrd,
+    "--step", "300",
+    "DS:a:GAUGE:600:U:U",
+    "DS:b:GAUGE:600:U:U",
+    "RRA:AVERAGE:0.5:1:300")
+
+=head1 DESCRIPTION
+
+The B<rrdtool> functions are directly callable via the Ruby programming
+language. This wrapper implementation has been written from the scratch
+(without  SWIG)
+
+The API's simply expects string parameters to the functions.  Please refer
+to the other B<rrdtool> documentation for functions and valid arguments.
+
+=head1 EXAMPLE
+
+ $: << '/path/to/rrdtool/lib/ruby/1.8/i386-linux'
+ require "RRD" 
+
+ name = "test"
+ rrd = "#{name}.rrd"
+ start = Time.now.to_i
+
+ RRD.create(    
+    rrd,
+    "--start", "#{start - 1}",
+    "--step", "300",
+        "DS:a:GAUGE:600:U:U",
+    "DS:b:GAUGE:600:U:U",
+    "RRA:AVERAGE:0.5:1:300")
+ puts
+
+ puts "updating #{rrd}"
+ start.to_i.step(start.to_i + 300 * 300, 300) { |i|
+    RRD.update(rrd, "#{i}:#{rand(100)}:#{Math.sin(i / 800) * 50 + 50}")
+ }
+ puts
+
+ puts "fetching data from #{rrd}"
+ (fstart, fend, data) = RRD.fetch(rrd, "--start", start.to_s, "--end", 
+      (start + 300 * 300).to_s, "AVERAGE")
+ puts "got #{data.length} data points from #{fstart} to #{fend}"
+ puts
+
+ puts "generating graph #{name}.png"
+ RRD.graph(
+   "#{name}.png",
+    "--title", " RubyRRD Demo", 
+    "--start", "#{start+3600}",
+    "--end", "start + 1000 min",
+    "--interlace", 
+    "--imgformat", "PNG",
+    "--width=450",
+    "DEF:a=#{rrd}:a:AVERAGE",
+    "DEF:b=#{rrd}:b:AVERAGE",
+    "CDEF:line=TIME,2400,%,300,LT,a,UNKN,IF",
+    "AREA:b#00b6e4:beta",
+    "AREA:line#0022e9:alpha",
+    "LINE3:line#ff0000") 
+ puts
+
+If you use the B<--ruby-site-install> configure option you can drop the $:
+line since the rrdtool module will be found automatically.
+
+If rrdtool runs into trouble, it will throw an exception which you might
+want to catch.
+
+=head1 SEE ALSO
+
+rrdcreate, rrdupdate, rrdgraph, rrddump, rrdfetch, rrdtune, rrdlast,
+rrdxport, rrdinfo
+
+=head1 AUTHOR
+
+Loïs Lherbier E<lt>lois.lherbier@covadis.chE<gt>
+
+Miles Egan E<lt>miles@caddr.comE<gt>
index 00f5e02d91f1388e71a69743b5c0d63935a3a91c..ace7ee8c395c0d0eb4d95e1aaab036f3a03bce8b 100644 (file)
@@ -1,6 +1,6 @@
 =head1 NAME
 
- rrdthreads - Provisions for linking the RRD library to use in multi-threaded programs
+rrdthreads - Provisions for linking the RRD library to use in multi-threaded programs
 
 =head1 SYNOPSIS
 
@@ -9,37 +9,37 @@ precautions, as the RRD library in its original form was not
 thread-safe at all. This document describes requirements and pitfalls
 on the way to use the multi-threaded version of librrd in your own
 programs. It also gives hints for future RRD development to keep the
-library thread-safe..
+library thread-safe.
 
 Currently only some RRD operations are implemented in a thread-safe
-way. They all end in the usual "C<_r>" prefix.
+way. They all end in the usual "C<_r>" suffix.
 
 =head1 DESCRIPTION
 
-In order to use the librrd in multi-threaded programs you must:
+In order to use librrd in multi-threaded programs you must:
 
-=over 4
+=over
 
-=item * 
+=item *
 
-Link with F<librrd_th> instead of with F<librrd> (use C<-lrrd_th> when
+Link with F<librrd_th> instead of F<librrd> (use C<-lrrd_th> when
 linking)
 
-=item * 
+=item *
 
-Use the "C<_r>" functions instead or the normal API-functions
+Use the "C<_r>" functions instead of the normal API-functions
 
-=item * 
+=item *
 
 Do not use any at-style time specifications. Parsing of such time
 specifications is terribly non-thread-safe.
 
-=item * 
+=item *
 
 Never use non *C<_r> functions unless it is explicitly documented that
-the function is tread-safe
+the function is tread-safe.
 
-=item * 
+=item *
 
 Every thread SHOULD call C<rrd_get_context()> before its first call to
 any C<librrd_th> function in order to set up thread specific data. This
@@ -54,19 +54,19 @@ library. Otherwise the call might fail due to some earlier error.
 
 =back
 
-=head1 IMPORTANT NOTES FOR RRD CONTRIBUTORS:
+=head2 NOTES FOR RRD CONTRIBUTORS
 
 Some precautions must be followed when developing RRD from now on:
 
-=over 4
+=over
 
 =item *
 
 Only use thread-safe functions in library code. Many often used libc
 functions aren't thread-safe. Take care in the following
-situations/when using the following library functions:
+situations or when using the following library functions:
 
-=over 8
+=over
 
 =item *
 
@@ -93,11 +93,13 @@ C<tmpnam>: use C<tmpnam_r>
 
 =item *
 
-Many other (lookup documentation)
+Many others (lookup documentation)
 
 =back
 
-As an aide(?) a header file named F<rrd_is_thread_safe.h> is provided
+=item *
+
+A header file named F<rrd_is_thread_safe.h> is provided
 that works with the GNU C-preprocessor to "poison" some of the most
 common non-thread-safe functions using the C<#pragma GCC poison>
 directive. Just include this header in source files you want to keep
@@ -113,8 +115,8 @@ F<rrd_thread_safe.c> and F<rrd_non_thread_safe.c>
 
 =item *
 
-Do not use C<getopt> or C<getopt_long> in *C<_r> (directly or
-indirectly)
+Do not use C<getopt> or C<getopt_long> in *C<_r> (neither directly nor
+indirectly).
 
 C<getopt> uses global variables and behaves badly in a multi-threaded
 application when called concurrently. Instead provide a *_r function
@@ -126,25 +128,17 @@ C<rrd_update_r> as an example.
 
 Do not use the C<parsetime> function!
 
-It uses lots of global vars. You may use it in functions not designed
-to be thread-safe like functions wrapping the C<_r> version of some
+It uses lots of global variables. You may use it in functions not designed
+to be thread-safe, like in functions wrapping the C<_r> version of some
 operation (e.g., C<rrd_create>, but not in C<rrd_create_r>)
 
 =back
 
-=head1 CURRENTLY IMPLEMENTED THREAD SAFE FUNCTIONS
+=head2 CURRENTLY IMPLEMENTED THREAD SAFE FUNCTIONS
 
-Currently there exit thread-safe variants of C<rrd_update>,
-C<rrd_create>, C<rrd_dump>, C<rrd_info> and C<rrd_last>.
+Currently there exist thread-safe variants of C<rrd_update>,
+C<rrd_create>, C<rrd_dump>, C<rrd_info>, C<rrd_last>, and C<rrd_fetch>.
 
 =head1 AUTHOR
 
-Initial multi-threading support was implemented by Peter Stamfest
-<peter@stamfest.at> in Feb. 2003.
-
-This documentation was written by Peter Stamfest.
-
-Changes to the RRD library and this documentation are (c) 2003 by
-Peter Stamfest and are distributed under the GPL.
-
-=cut
+Peter Stamfest E<lt>peter@stamfest.atE<gt>
index 4f575e3b6269e0d8e9a928b83fdf0dd46df29780..0e68015151a3e4c21cccabcb7a9c09410be33d01 100644 (file)
@@ -2,7 +2,7 @@
 <!-- the attributes of the row and the t elements are used -->
 <!-- in the examples/shared-demo.pl, but not in the output -->
 <!-- of the native xport command.                          -->
-<!-- wolfgang{dot}schrimm{at}urz{dot}uni-heidelberg{dot}de                -->
+<!-- wolfgang{dot}schrimm{at}urz{dot}uni-heidelberg{dot}de -->
 
 <!-- root element -->
 <!ELEMENT xport (meta, data)>
index 58a85615dffa0a3cd2a6fb6b68a782656157375d..cd3c785244c065fb1db4202f1d4a039658061a65 100644 (file)
@@ -1,8 +1,6 @@
 =head1 NAME
 
-rrdtool - round robin database tool
-
-=for html <div align="right"><a href="rrdtool.pdf">PDF</a> version.</div>
+rrdtool - Round Robin Database Tool
 
 =head1 SYNOPSIS
 
@@ -15,8 +13,8 @@ B<rrdtool> B<-> [workdir]| I<function>
 It is pretty easy to gather status information from all sorts of
 things, ranging from the temperature in your office to the number of
 octets which have passed through the FDDI interface of your
-router. But it is not so trivial to store this data in a efficient and
-systematic manner. This is where B<RRDtool> kicks in. It lets you
+router. But it is not so trivial to store this data in an efficient and
+systematic manner. This is where B<RRDtool> comes in handy. It lets you
 I<log and analyze> the data you gather from all kinds of data-sources
 (B<DS>). The data analysis part of RRDtool is based on the ability to
 quickly generate graphical representations of the data values
@@ -24,21 +22,22 @@ collected over a definable time period.
 
 In this man page you will find general information on the design and
 functionality of the Round Robin Database Tool (RRDtool). For a more
-detailed description of how to use the individual functions of the
+detailed description of how to use the individual functions of
 B<RRDtool> check the corresponding man page.
 
-For an introduction to the usage of RRDtool make sure you check L<rrdtutorial>.
+For an introduction to the usage of RRDtool make sure you consult the
+L<rrdtutorial>.
 
 =head2 FUNCTIONS
 
 While the man pages talk of command line switches you have to set in
-order to make B<RRDtool> work it is important to note that the
+order to make B<RRDtool> work it is important to note that
 B<RRDtool> can be remotely controlled through a set of pipes. This
 saves a considerable amount of startup time when you plan to make
 B<RRDtool> do a lot of things quickly. Check the section on L<"Remote
 Control"> further down. There is also a number of language bindings
 for RRDtool which allow you to use it directly from perl, python, tcl,
-php, ...
+php, etc.
 
 =over 8
 
@@ -52,22 +51,22 @@ Store new data values into an RRD. Check L<rrdupdate>.
 
 =item B<updatev>
 
-Operation equivalent to B<update> except for output. Check L<rrdupdate>.
+Operationally equivalent to B<update> except for output. Check L<rrdupdate>.
 
 =item B<graph>
 
-Create a graph from data stored in one or several RRD. Apart from
+Create a graph from data stored in one or several RRDs. Apart from
 generating graphs, data can also be extracted to stdout. Check L<rrdgraph>.
 
 =item B<dump>
 
-Dump the contents of an RRD in plain ASCII. In connection with 
-restore you can use it to transport an RRD from one architecture to another.
-Check L<rrddump>.
+Dump the contents of an RRD in plain ASCII. In connection with restore
+you can use this to move an RRD from one computer architecture to
+another.  Check L<rrddump>.
 
 =item B<restore>
 
-Restore an RRD in XML format to a binary RRD ... Check L<rrdrestore>
+Restore an RRD in XML format to a binary RRD. Check L<rrdrestore>
 
 =item B<fetch>
 
@@ -80,7 +79,7 @@ Alter setup of an RRD. Check L<rrdtune>.
 
 =item B<last>
 
-Find last update time of an RRD. Check L<rrdlast>.
+Find the last update time of an RRD. Check L<rrdlast>.
 
 =item B<info>
 
@@ -88,11 +87,11 @@ Get information about an RRD. Check L<rrdinfo>.
 
 =item B<rrdresize>
 
-Change the size of individual RRAs ... Dangerous! Check L<rrdresize>.
+Change the size of individual RRAs. This is dangerous! Check L<rrdresize>.
 
 =item B<xport>
 
-Export data retrieved from one or several RRD. Check L<rrdxport>
+Export data retrieved from one or several RRDs. Check L<rrdxport>
 
 =item B<rrdcgi>
 
@@ -105,78 +104,81 @@ L<rrdcgi>.
 
 =over 8
 
-=item Data acquisition
+=item Data Acquisition
 
 When monitoring the state of a system, it is convenient to have the
-data available at a constant interval. Unfortunately you may not
+data available at a constant time interval. Unfortunately, you may not
 always be able to fetch data at exactly the time you want
 to. Therefore B<RRDtool> lets you update the logfile at any time you
 want. It will automatically interpolate the value of the data-source
-(B<DS>) at the latest official time-slot and write this value to the
-log. The value you have supplied is stored as well and is also taken
-into account when interpolating the next log entry.
+(B<DS>) at the latest official time-slot (intervall) and write this
+interpolated value to the log. The original value you have supplied is
+stored as well and is also taken into account when interpolating the
+next log entry.
 
 =item Consolidation
 
-You may log data at a 1 minute interval, but you are also be
+You may log data at a 1 minute interval, but you might also be
 interested to know the development of the data over the last year. You
-could do this by simply storing the data in 1 minute interval, for one
-year. While this would take considerable disk space it would also take
-a lot of time to analyze the data when you wanted to create a graph
-covering the whole year. B<RRDtool> offers a solution to this of this
-problem through its data consolidation feature. When setting up
-an Round Robin Database (B<RRD>), you can define at which interval
-this consolidation should occur, and what consolidation function
-(B<CF>) (average, minimum, maximum, total, last) should be used to
-build the consolidated values (see rrdcreate). You can define any
-number of different consolidation setups within one B<RRD>. They will
-all be maintained on the fly when new data is loaded into the B<RRD>.
+could do this by simply storing the data in 1 minute intervals for the
+whole year. While this would take considerable disk space it would
+also take a lot of time to analyze the data when you wanted to create
+a graph covering the whole year. B<RRDtool> offers a solution to this
+problem through its data consolidation feature. When setting up an
+Round Robin Database (B<RRD>), you can define at which interval this
+consolidation should occur, and what consolidation function (B<CF>)
+(average, minimum, maximum, total, last) should be used to build the
+consolidated values (see rrdcreate). You can define any number of
+different consolidation setups within one B<RRD>. They will all be
+maintained on the fly when new data is loaded into the B<RRD>.
 
 =item Round Robin Archives
 
 Data values of the same consolidation setup are stored into Round
 Robin Archives (B<RRA>). This is a very efficient manner to store data
-for a certain amount of time, while using a known amount of storage
-space. 
-
-It works like this: If you want to store 1000 values in 5 minute
-interval, B<RRDtool> will allocate space for 1000 data values and a
-header area. In the header it will store a pointer telling
-which one of the values in the storage area was last written to. New
-values are written to the Round Robin Archive in a ...  you guess it
-... round robin manner. This automatically limits the history to the last
-1000 values. Because you can define several B<RRA>s within a single B<RRD>,
-you can setup another one, storing 750 data values at a 2 hour interval
-and thus keeping a log for the last two months although at a lower
-resolution.
+for a certain amount of time, while using a known and constant amount
+of storage space.
+
+It works like this: If you want to store 1'000 values in 5 minute
+interval, B<RRDtool> will allocate space for 1'000 data values and a
+header area. In the header it will store a pointer telling which slots
+(value) in the storage area was last written to. New values are
+written to the Round Robin Archive in, you guessed it, a round robin
+manner. This automatically limits the history to the last 1'000 values
+(in our example). Because you can define several B<RRA>s within a
+single B<RRD>, you can setup another one, for storing 750 data values
+at a 2 hour interval, for example, and thus keep a log for the last
+two months at a lower resolution.
 
 The use of B<RRA>s guarantees that the B<RRD> does not grow over
 time and that old data is automatically eliminated. By using the
 consolidation feature, you can still keep data for a very long time,
 while gradually reducing the resolution of the data along the time
-axis. Using different consolidation functions (B<CF>) allows you to
-store exactly the type of information that actually interests
-you. (Maximum one minute traffic on the LAN, minimum temperature of
-the wine cellar, total minutes down time ...)
+axis.
+
+Using different consolidation functions (B<CF>) allows you to store
+exactly the type of information that actually interests you: the maximum
+one minute traffic on the LAN, the minimum temperature of your wine cellar,
+the total minutes of down time, etc.
 
 =item Unknown Data
 
 As mentioned earlier, the B<RRD> stores data at a constant
-interval. Now it may happen that no new data is available when a
+interval. Sometimes it may happen that no new data is available when a
 value has to be written to the B<RRD>. Data acquisition may not be
-possible for one reason or an other. The B<RRDtool> handles these
+possible for one reason or other. With B<RRDtool> you can handle these
 situations by storing an I<*UNKNOWN*> value into the database. The
 value 'I<*UNKNOWN*>' is supported through all the functions of the
-database. When consolidating the amount of I<*UNKNOWN*> data is
-accumulated and when a new consolidated value is ready to be written
-to its Round Robin Archive (B<RRA>) a validity check is performed to
-make sure that the percentage of unknown data in the new value is
-below a configurable level. If so, an I<*UNKNOWN*> value will be
-written to the B<RRA>.
+tool. When consolidating a data set, the amount of I<*UNKNOWN*> data
+values is accounted for and when a new consolidated value is ready to
+be written to its Round Robin Archive (B<RRA>), a validity check is
+performed to make sure that the percentage of unknown values in the
+data point is above a configurable level. If not, an I<*UNKNOWN*> value
+will be written to the B<RRA>.
 
 =item Graphing
 
-The B<RRDtool> also allows one to generate reports in numerical and
+B<RRDtool> allows you to generate reports in numerical and
 graphical form based on the data stored in one or several
 B<RRD>s. The graphing feature is fully configurable. Size, color and
 contents of the graph can be defined freely. Check L<rrdgraph>
@@ -184,106 +186,117 @@ for more information on this.
 
 =item Aberrant Behavior Detection
 
-by Jake Brutlag E<lt>jakeb@corp.webtv.netE<gt>
+by Jake Brutlag
 
-The  B<RRDtool> also provides the building blocks for near real-time
-aberrant behavior detection. These components include:
+B<RRDtool> provides the building blocks for near real-time aberrant
+behavior detection. These components include:
 
-=over 12
+=over
 
 =item *
 
-An algorithm for predicting the values time series one time step into the future.
+An algorithm for predicting the value of a time series one time step
+into the future.
 
 =item *
 
-A measure of deviation between the predicted values and the observed values.
+A measure of deviation between predicted and observed values.
 
 =item *
 
-A mechanism to decide if and when an observed value
-or sequence of observed values is I<too deviant> from the predicted value(s).
+A mechanism to decide if and when an observed value or sequence of
+observed values is I<too deviant> from the predicted value(s).
 
 =back
 
-Each of these components is briefly described:
-
-Holt-Winters Time Series forecasting algorithm is an on-line, or incremental, 
-algorithm that adaptively predicts future observations in a time series. It's 
-forecast is the sum of three components: a baseline (or intercept), a linear 
-trend over time (or slope), and a seasonal coefficient (a periodic effect, 
-such as a daily cycle). There is one seasonal coefficient for each time point 
-in the period (cycle). After a value is observed, each of these components is 
-updated via exponential smoothing. So the algorithm learns from past values 
-and uses them to predict the future. The rate of adaptation is governed by 
-3 parameters, alpha (intercept), beta (slope), and gamma (seasonal). The prediction 
-can also be viewed as a smoothed value for the time series.
-
-The measure of deviation is a seasonal weighted absolute deviation. The term 
-I<seasonal> means deviation is measured separately for each time point in the 
-seasonal cycle. As with Holt-Winters forecasting, deviation is predicted using 
-the measure computed from past values (but only at that point in the seasonal cycle). 
-After the value is observed, the algorithm learns from the observed value via 
-exponential smoothing. Confidence bands for the observed time series are generated 
-by scaling the sequence of predicted deviation values (we usually think of the sequence 
-as a continuous line rather than a set of discrete points).
-
-Aberrant behavior (a potential failure) is reported whenever the number of 
-times the observed value violates the confidence bands meets or exceeds a 
-specified threshold within a specified temporal window (i.e. 5 violations 
-during the past 45 minutes with a value observed every 5 minutes).
-
-This functionality is embedded in a set of related B<RRAs>. In particular, a FAILURES
-B<RRA> logs potential failures. Presumably a front-end application to B<RRDtool> can
-utilize this B<RRA> to initiate real-time alerts if that is desired.
-
-You can find a detailed description of how to set this up in L<rrdcreate>.
+Here is a brief explanation of these components:
+
+The Holt-Winters time series forecasting algorithm is an on-line (or
+incremental) algorithm that adaptively predicts future observations in
+a time series. Its forecast is the sum of three components: a baseline
+(or intercept), a linear trend over time (or slope), and a seasonal
+coefficient (a periodic effect, such as a daily cycle). There is one
+seasonal coefficient for each time point in the period (cycle). After
+a value is observed, each of these components is updated via
+exponential smoothing. This means that the algorithm "learns" from
+past values and uses them to predict the future. The rate of
+adaptation is governed by 3 parameters, alpha (intercept), beta
+(slope), and gamma (seasonal). The prediction can also be viewed as a
+smoothed value for the time series.
+
+The measure of deviation is a seasonal weighted absolute
+deviation. The term I<seasonal> means deviation is measured separately
+for each time point in the seasonal cycle. As with Holt-Winters
+forecasting, deviation is predicted using the measure computed from
+past values (but only at that point in the seasonal cycle). After the
+value is observed, the algorithm learns from the observed value via
+exponential smoothing. Confidence bands for the observed time series
+are generated by scaling the sequence of predicted deviation values
+(we usually think of the sequence as a continuous line rather than a
+set of discrete points).
+
+Aberrant behavior (a potential failure) is reported whenever the
+number of times the observed value violates the confidence bands meets
+or exceeds a specified threshold within a specified temporal window
+(e.g. 5 violations during the past 45 minutes with a value observed
+every 5 minutes).
+
+This functionality is embedded in a set of related B<RRAs>. In
+particular, a FAILURES B<RRA> logs potential failures. With these data
+you could, for example, use a front-end application to B<RRDtool> to
+initiate real-time alerts.
+
+For a detailed description on how to set this up, see L<rrdcreate>.
 
 =back
 
 =head2 REMOTE CONTROL
 
-When you start B<RRDtool> with the command line option 'B<->', it waits
-for input via standard in. With this feature you can improve
-performance by attaching B<RRDtool> to another process (MRTG is one
-example) through a set of pipes. Over the pipes B<RRDtool> accepts the
-same arguments as on the command line and some special commands like
-B<quit, cd, mkdir> and B<ls>. For detail helps about the server commands
-type :
-
-   rrdtool help cd|mkdir|ls|quit
-
-When a command is completed, RRDtool will print the string  'C<OK>', 
-followed by timing information of the form B<u:>I<usertime> 
-B<s:>I<systemtime> both values are running totals of seconds 
-since RRDtool was started. If an error occurs, a line of the 
-form 'C<ERROR:> I<Description of error>' will be printed. B<RRDtool>
-will not abort if possible, but follow the ERROR line with an OK line.
-If a B<workdir> is specified and the UID is 0, RRDtool will do a 
-chroot to the workdir. If the UID is not 0, RRDtool only changes the
-current directory to B<workdir>.
+When you start B<RRDtool> with the command line option 'B<->' it waits
+for input via standard input (STDIN). With this feature you can
+improve performance by attaching B<RRDtool> to another process (MRTG
+is one example) through a set of pipes. Over these pipes B<RRDtool>
+accepts the same arguments as on the command line and some special
+commands like B<quit, cd, mkdir> and B<ls>. For detailed help on the
+server commands type:
+
+   rrdtool help cd|mkdir|pwd|ls|quit
+
+When a command is completed, RRDtool will print the string  'C<OK>',
+followed by timing information of the form B<u:>I<usertime>
+B<s:>I<systemtime>. Both values are the running totals of seconds since
+RRDtool was started. If an error occurs, a line of the form 'C<ERROR:>
+I<Description of error>' will be printed instead. B<RRDtool> will not abort,
+unless something realy serious happens. If
+a B<workdir> is specified and the UID is 0, RRDtool will do a chroot to that
+workdir. If the UID is not 0, RRDtool only changes the current directory to
+B<workdir>.
 
 =head2 RRD Server
 
-If you want to create a RRD-Server, you must choose a TCP/IP Service 
+If you want to create a RRD-Server, you must choose a TCP/IP Service
 number and add them to I</etc/services> like this:
 
  rrdsrv      13900/tcp                       # RRD server
 
-Attention: the TCP port 13900 isn't official registered for rrdsrv. You
-can use any unused port in your services, but the server an the client
-system must use the same port of curse.
-After this you can add the RRDtool as meta-server to I</etc/inetd.conf>
-for example:
-  
+Attention: the TCP port 13900 isn't officially registered for
+rrdsrv. You can use any unused port in your services file, but the
+server and the client system must use the same port, of course.
+
+With this configuration you can add RRDtool as meta-server to
+I</etc/inetd.conf>. For example:
+
  rrdsrv stream tcp nowait root /opt/rrd/bin/rrdtool rrdtool - /var/rrd
 
-Don't forget to create the database directory /var/rrd and reinitialize
-your inetd.
-If all was correct, you can access the server with perl sockets, tools
-like netcat or a quick test 'telnet localhost rrdsrv'.
+Don't forget to create the database directory /var/rrd and
+reinitialize your inetd.
 
+If all was setup correctly, you can access the server with perl
+sockets, tools like netcat, or in a quick interactive test by using
+'telnet localhost rrdsrv'.
 
+B<NOTE:> that there is no authentication with this feature! Do not setup
+such a port unless you are sure what you are doing.
 
 =head1 SEE ALSO
 
@@ -291,9 +304,9 @@ rrdcreate, rrdupdate, rrdgraph, rrddump, rrdfetch, rrdtune, rrdlast, rrdxport
 
 =head1 BUGS
 
-Bugs ? Features !
+Bugs? Features!
 
 =head1 AUTHOR
 
-Tobias Oetiker <oetiker@ee.ethz.ch>
+Tobias Oetiker <tobi@oetiker.ch>
 
index c4175a77cd9362a09f896cf41457bfebe7c7c609..5e9029bf12a2772a4267c249262645e59fee2e7b 100644 (file)
@@ -1,13 +1,11 @@
 =head1 NAME
 
-rrdtool tune - Modify some basic properties of a Round Robin Database
-
-=for html <div align="right"><a href="rrdtune.pdf">PDF</a> version.</div>
+rrdtune - Modify some basic properties of a Round Robin Database
 
 =head1 SYNOPSIS
 
-B<rrdtool> B<tune> I<filename> 
-S<[B<--heartbeat>|B<-h> I<ds-name>:I<heartbeat>]> 
+B<rrdtool> B<tune> I<filename>
+S<[B<--heartbeat>|B<-h> I<ds-name>:I<heartbeat>]>
 S<[B<--minimum>|B<-i> I<ds-name>:I<min>]>
 S<[B<--maximum>|B<-a> I<ds-name>:I<max>]>
 S<[B<--data-source-type>|B<-d> I<ds-name>:I<DST>]>
@@ -27,7 +25,7 @@ S<[B<--aberrant-reset> I<ds-name>]>
 The tune option allows you to alter some of the basic configuration
 values stored in the header area of a Round Robin Database (B<RRD>).
 
-One application of the B<tune> function is to relax the 
+One application of the B<tune> function is to relax the
 validation rules on an B<RRD>. This allows to fill a new B<RRD> with
 data available in larger intervals than what you would normally want
 to permit. Be very careful with tune operations for COMPUTE data sources.
@@ -47,7 +45,7 @@ The name of the B<RRD> you want to tune.
 =item S<B<--heartbeat>|B<-h> I<ds-name>:I<heartbeat>>
 
 modify the I<heartbeat> of a data source. By setting this to a high
-value the RRD will accept things like one value per day ...
+value the RRD will accept things like one value per day.
 
 =item S<B<--minimum>|B<-i> I<ds-name>:I<min>>
 
@@ -65,16 +63,17 @@ alter the type B<DST> of a data source.
 
 =item S<B<--data-source-rename>|B<-r> I<old-name>:I<new-name>>
 
-rename a data source
+rename a data source.
 
 =item S<B<--deltapos> I<scale-value>>
 
-Alter the deviation scaling factor for the upper bound of the confidence band
-used internally to calculate violations for the FAILURES B<RRA>. The default
-value is 2. Note that this parameter is not related to graphing confidence
-bounds, that scale factor must be specified as a CDEF argument to generate 
-a graph with confidence bounds. The graph scale factor need not agree with the 
-value used internally by the FAILURES B<RRA>.
+Alter the deviation scaling factor for the upper bound of the
+confidence band used internally to calculate violations for the
+FAILURES B<RRA>. The default value is 2. Note that this parameter is
+not related to graphing confidence bounds which must be specified as a
+CDEF argument to generate a graph with confidence bounds. The graph
+scale factor need not to agree with the value used internally by the
+FAILURES B<RRA>.
 
 =item S<B<--deltaneg> I<scale-value>>
 
@@ -88,40 +87,40 @@ factor chosen when graphing confidence bounds.
 Alter the number of confidence bound violations that constitute a failure for
 purposes of the FAILURES B<RRA>. This must be an integer less than or equal to
 the window length of the FAILURES B<RRA>. This restriction is not verified by
-the tune option, so one can reset failure-threshold and window-length 
+the tune option, so one can reset failure-threshold and window-length
 simultaneously. Setting this option will reset the count of violations to 0.
 
 =item S<B<--window-length> I<window-length>>
 
-Alter the number of time points in the temporal window for determining failures.
-This must be an integer greater than or equal to the window length of the
-FAILURES B<RRA> and less than or equal to 28. Setting this option will reset the
-count of violations to 0.
+Alter the number of time points in the temporal window for determining
+failures. This must be an integer greater than or equal to the window
+length of the FAILURES B<RRA> and less than or equal to 28. Setting
+this option will reset the count of violations to 0.
 
 =item S<B<--alpha> I<adaption-parameter>>
 
-Alter the intercept adaptation parameter for the Holt-Winters forecasting algorithm.
-Must be between 0 and 1.
+Alter the intercept adaptation parameter for the Holt-Winters
+forecasting algorithm. This parameter must be between 0 and 1.
 
 =item S<B<--beta> I<adaption-parameter>>
 
-Alter the slope adaptation parameter for the Holt-Winters forecasting algorithm.
-Must be between 0 and 1.
+Alter the slope adaptation parameter for the Holt-Winters forecasting
+algorithm. This parameter must be between 0 and 1.
 
 =item S<B<--gamma> I<adaption-parameter>>
 
 Alter the seasonal coefficient adaptation parameter for the SEASONAL
-B<RRA>. Must be between 0 and 1.
+B<RRA>. This parameter must be between 0 and 1.
 
 =item S<B<--gamma-deviation> I<adaption-parameter>>
 
 Alter the seasonal deviation adaptation parameter for the DEVSEASONAL
-B<RRA>. Must be between 0 and 1.
+B<RRA>. This parameter must be between 0 and 1.
 
 =item S<B<--aberrant-reset> I<ds-name>>
 
 This option causes the aberrant behavior detection algorithm to reset
-for the specified data source; that is, forget all it is has learn.
+for the specified data source; that is, forget all it is has learnt so far.
 Specifically, for the HWPREDICT B<RRA>, it sets the intercept and slope
 coefficients to unknown. For the SEASONAL B<RRA>, it sets all seasonal
 coefficients to unknown. For the DEVSEASONAL B<RRA>, it sets all seasonal
@@ -138,11 +137,11 @@ initialization this smoothing is deferred. For efficiency, the implementation
 of smoothing is not data source specific. This means that utilizing
 reset for one data source will delay running the smoothing algorithm
 for all data sources in the file. This is unlikely to have serious
-consequences, unless the data being collected for the non-reset data sources 
-is unusually volatile during the reinitialization period of the reset 
+consequences, unless the data being collected for the non-reset data sources
+is unusually volatile during the reinitialization period of the reset
 data source.
 
-Use of this tuning option is advised when the behavior of the data source 
+Use of this tuning option is advised when the behavior of the data source
 time series changes in a drastic and permanent manner.
 
 =back
@@ -151,8 +150,8 @@ time series changes in a drastic and permanent manner.
 
 C<rrdtool tune data.rrd -h in:100000 -h out:100000 -h through:100000>
 
-Set the minimum required heartbeat for data sources 'in', 'out' 
-and 'through' to 10000 seconds which is a little over one day in data.rrd.
+Set the minimum required heartbeat for data sources 'in', 'out'
+and 'through' to 10'000 seconds which is a little over one day in data.rrd.
 This would allow to feed old data from MRTG-2.0 right into
 RRDtool without generating *UNKNOWN* entries.
 
@@ -160,11 +159,12 @@ RRDtool without generating *UNKNOWN* entries.
 
 C<rrdtool tune monitor.rrd --window-length 5 --failure-threshold 3>
 
-If the FAILURES B<RRA> is implicitly created, the default window-length is 9 and 
-the default failure-threshold is 7. This command now defines a failure as 3 or more
-violations in a temporal window of 5 time points.
+If the FAILURES B<RRA> is implicitly created, the default
+window-length is 9 and the default failure-threshold is 7. This
+command now defines a failure as 3 or more violations in a temporal
+window of 5 time points.
 
 =head1 AUTHOR
 
-Tobias Oetiker <oetiker@ee.ethz.ch>
+Tobias Oetiker <tobi@oetiker.ch>
 
index 9fb97aea609b1cccb336495613d1922527e613f6..16173f0d2d89037f7ef983437908ddb3fe1f76c0 100644 (file)
@@ -107,7 +107,7 @@ las listas de correo, no s
 con RRDtool para ver donde está el archivo y como usarlo.
 
 Te sugiero que te tomes un momento y te subscribas a la lista ahora
-mismo, enviando un mensaje a rrd-users-request@list.ee.ethz.ch
+mismo, enviando un mensaje a rrd-users-request@lists.oetiker.ch
 con título C<subscribe>. Si eventualmente deseas salirte de la lista,
 envía otro correo a la misma dirección, con título C<unsubscribe>.
 
@@ -147,7 +147,7 @@ byte son 8 bits y empecemos a pensar en bits y no en bytes. 
 contador, sin embargo, sigue contando en bytes! En el mundo
 SNMP, la mayoría de los contadores tienen una
 longitud de 32 bits. Esto significa que pueden contar desde 0 hasta
-4294967295. Usaremos estos valores en los ejemplos. El dispositivo, cuando 
+4294967295. Usaremos estos valores en los ejemplos. El dispositivo, cuando
 le preguntamos, retorna el valor actual del contador. Como sabemos el
 tiempo transcurrido desde la Ãºltima vez que le preguntamos, sabemos
 cuantos bytes se han transferido C<***en promedio***> por
@@ -286,7 +286,7 @@ siguientes valores:
 
  fecha 920804700, valor 12345
  fecha 920805000, valor 12357
+
  etcétera.
 
 Como ves, pueden introducirse más de un valor en la base de datos
@@ -300,7 +300,7 @@ Ahora podemos recuperar los datos usando ``rrdtool fetch'':
 Debes obtener esto como salida:
 
                     speed
+
  920804400:        NaN
  920804700:        NaN
  920805000: 4.0000000000e-02
@@ -438,7 +438,7 @@ colores de la velocidad, y ahora paso de ser una l
 
 Los cálculos son más complejos ahora. Para calcular la velocidad "aceptable":
 
-   Verifica si la velocidad en kmh es mayor que 100     ( kmh,100 ) GT           
+   Verifica si la velocidad en kmh es mayor que 100     ( kmh,100 ) GT
    Si es así, retorna 0, si no, retorna la velocidad    ((( kmh,100 ) GT ), 0, kmh) IF
 
 Para calcular la parte de velocidad "excesiva":
@@ -570,7 +570,7 @@ De acuerdo, sigamos con el inicio de nuestro OID: ten
 1.3.6.1.2.1 . Ahora, nos interesa la rama ``interfaces'', que tiene el
 número dos (o sea, 1.3.6.1.2.1.2, o 1.3.6.1.2.1.interfaces).
 
-Lo primero es hacernos con un programa SNMP. Busca algún 
+Lo primero es hacernos con un programa SNMP. Busca algún
 paquete pre-compilado para tu plataforma, si no, puedes
 buscar el código fuente y compilarlo tu mismo. En Internet encontrarás
 muchos programas, búscalos con un motor de búsqueda o como prefieras.
@@ -604,7 +604,7 @@ adelante con otro programa, llamado "snmpwalk"
 Si obtienes una lista de interfaces, ya casi hemos llegado. Aquí
 tienes un ejemplo del resultado:
 
-   [user@host /home/alex]$ snmpwalk cisco public 2.2.1.2   
+   [user@host /home/alex]$ snmpwalk cisco public 2.2.1.2
    interfaces.ifTable.ifEntry.ifDescr.1 = "BRI0: B-Channel 1"
    interfaces.ifTable.ifEntry.ifDescr.2 = "BRI0: B-Channel 2"
    interfaces.ifTable.ifEntry.ifDescr.3 = "BRI0" Hex: 42 52 49 30
@@ -615,16 +615,16 @@ En este equipo CISCO, quiero monitorizar la interfaz "Ethernet0".
 Viendo que es la cuarta, pruebo con:
 
    [user@host /home/alex]$ snmpget cisco public 2.2.1.10.4 2.2.1.16.4
+
    interfaces.ifTable.ifEntry.ifInOctets.4 = 2290729126
    interfaces.ifTable.ifEntry.ifOutOctets.4 = 1256486519
 
 Entonces, tengo 2 OIDs que monitorizar, y son (en el formato largo, ahora):
 
    1.3.6.1.2.1.2.2.1.10
+
         y
+
    1.3.6.1.2.1.2.2.1.16
 
 , ambas con el número de interfaz de 4
@@ -693,7 +693,7 @@ buscar exactamente como hacerlo funcionar en tu sistema operativo.
 
    mientras no sea el fin del universo
    hacer
-      tomar el resultado de 
+      tomar el resultado de
           snmpget router community 2.2.1.10.4
       en la variable $in
       tomar el resultado de
@@ -944,13 +944,13 @@ empezaba en 0, as
 
 =item *
 
-Línea B: 
+Línea B:
 No hay nada que calcular, los valores son los mismos que se
 introdujeron en la base de datos.
 
 =item *
 
-Línea C: 
+Línea C:
 De nuevo, no conocemos el valor
 inicial antes de la primera medición, así que se aplica el mismo
 razonamiento que para la línea A. En este
@@ -992,7 +992,7 @@ reinicializado! Si la diferencia es negativa, esto se compensa sumando
 el valor máximo del contador + 1. Para nuestro coche, tendríamos:
 
  Delta = 7 - 999987 = -999980    (en vez de 1000007-999987=20)
+
  Delta real= -999980 + 999999 + 1 = 20
 
 Al momento de escribir este documento, RRDtool maneja contadores de
 
  - 32 bits: (4294967295+1) =                                 4294967296
  - 64 bits: (18446744073709551615+1)-correction1 = 18446744069414584320
+
  Antes:          4294967200
  Incremento:            100
  Debería ser:    4294967300
  Pero es:                 4
  Diferencia:    -4294967196
  Corrección #1: -4294967196 + 4294967296 = 100
+
  Antes:          18446744073709551000
  Incremento:                      800
  Debería ser:    18446744073709551800
  Diferencia:    -18446744073709550816
  Corrección #1: -18446744073709550816 +4294967296 = -18446744069414583520
  Corrección #2: -18446744069414583520 +18446744069414584320 = 800
+
  Antes:          18446744073709551615 ( valor máximo )
- Incremento:     18446744069414584320 ( incremento absurdo, 
- Debería ser:    36893488143124135935   mínimo para que 
- Pero es:        18446744069414584319   funcione el ejemplo)       
+ Incremento:     18446744069414584320 ( incremento absurdo,
+ Debería ser:    36893488143124135935   mínimo para que
+ Pero es:        18446744069414584319   funcione el ejemplo)
  Diferencia:              -4294967296
  Corrección #1:  -4294967296 + 4294967296 = 0 (positivo,
-                                               por tanto no se hace 
+                                               por tanto no se hace
                                                la segunda corrección)
+
  Antes:          18446744073709551615 ( valor máximo )
- Incremento:     18446744069414584319 
+ Incremento:     18446744069414584319
  Debería ser:    36893488143124135934
  Pero es:        18446744069414584318
  Diferencia:              -4294967297
@@ -1109,7 +1109,7 @@ deber
 debe ser.
 
          en RRD                     en realidad
- tiempo+000:   0 delta="U"    tiempo+000:   0 delta="U" 
+ tiempo+000:   0 delta="U"    tiempo+000:   0 delta="U"
  tiempo+300: 300 delta=300    tiempo+300: 300 delta=300
  tiempo+600: 600 delta=300    tiempo+603: 603 delta=303
  tiempo+900: 900 delta=300    tiempo+900: 900 delta=297
index 2d42c64bd2926c9cec7743b43df120914090f2e3..385ed089b0374a8d9c741c34b08b4f92e9b58824 100644 (file)
@@ -2,13 +2,9 @@
 
 rrdtutorial - Alex van den Bogaerdt's RRDtool tutorial
 
-=for html <div align="right">Go <a href="rrdtutorial.es.html">Spanish</a></div> 
-
-=for html <div align="right"><a href="rrdtutorial.pdf">PDF</a> version.</div> 
-
 =head1 DESCRIPTION
 
-RRDtool is written by Tobias Oetiker <oetiker@ee.ethz.ch> with
+RRDtool is written by Tobias Oetiker <tobi@oetiker.ch> with
 contributions from many people all around the world. This document is
 written by Alex van den Bogaerdt <alex@ergens.op.het.net> to help you
 understand what RRDtool is and what it can do for you.
@@ -27,62 +23,69 @@ Please don't skip ahead in this document!  The first part of this
 document explains the basics and may be boring.  But if you don't
 understand the basics, the examples will not be as meaningful to you.
 
-=head2 What is RRDtool ?
+=head2 What is RRDtool?
 
 RRDtool refers to Round Robin Database tool.
 Round robin is a technique that works with a fixed amount of data, and a
 pointer to the current element. Think of a circle with some dots plotted
-on the edge, these dots are the places where data can be stored. Draw an
-arrow from the center of the circle to one of the dots, this is the pointer.
+on the edge -- these dots are the places where data can be stored. Draw an
+arrow from the center of the circle to one of the dots -- this is the pointer.
 When the current data is read or written, the pointer moves to the next
-element. As we are on a circle there is no beginning nor an end, you can
-go on and on. After a while, all the available places will be used and
-the process automatically reuses old locations. This way, the database
+element. As we are on a circle there is neither a beginning nor an end, you can
+go on and on and on. After a while, all the available places will be used and
+the process automatically reuses old locations. This way, the dataset
 will not grow in size and therefore requires no maintenance.
 RRDtool works with with Round Robin Databases (RRDs). It stores and retrieves
 data from them.
 
-=head2 What data can be put into an RRD ?
-
-You name it, it will probably fit. You should be able to measure some value
-at several points in time and provide this information to RRDtool. If you
-can do this, RRDtool will be able to store it. The values need to be
-numerical but don't have to be, as opposed to MRTG, integers.
-
-Many examples talk about SNMP which is an acronym for
-Simple Network Management Protocol. "Simple" refers to the protocol --
-it does not mean it is simple to manage or monitor a network. After working your
-way through this document, you should know enough to be able to understand
-what people are talking about. For now, just realize that SNMP is a way to
-ask devices for the values of counters they keep.
-It is the value from those counters that are kept in the RRD.
-
-=head2 What can I do with this tool ?
-
-RRDtool originated from MRTG (Multi Router Traffic Grapher).  MRTG started
-as a tiny little script for graphing the use of a connection
-to the Internet. MRTG evolved into a tool for graphing other data sources
-including temperature, speed, voltage, number of printouts and
-the like. Most likely you will start to use the RRDtool to store
-and process data collected via SNMP. The data will most likely be bytes
-(or bits) transfered from and to a network or a computer.
-RRDtool lets you create a database, store data in it, retrieve that data
-and create graphs in PNG format for display on a web browser. Those PNG
-images are dependent on the data you collected and could be, for instance,
-an overview of the average network usage, or the peaks that occurred.
-It can also be used to display tidal waves, solar radiation, power
-consumption, number of visitors at an exhibition, noise levels near an
-airport, temperature on your favorite holiday location, temperature in the
-fridge and whatever you imagination can come up with. You need a sensor to
-measure the data and be able to feed the numbers to RRDtool.
-
-=head2 What if I still have problems after reading this document ?
+=head2 What data can be put into an RRD?
+
+You name it, it will probably fit as long as it is some sort of time-series
+data. This means you have to be able to measure some value at several points in time and
+provide this information to RRDtool. If you can do this, RRDtool will be
+able to store it. The values must be numerical but don't have to be
+integers, as is the case with MRTG (the next section will give more details
+on this more specialized application).
+
+Many examples below talk about SNMP which is an acronym for Simple Network
+Management Protocol. "Simple" refers to the protocol -- it does not
+mean it is simple to manage or monitor a network. After working your
+way through this document, you should know enough to be able to
+understand what people are talking about. For now, just realize that
+SNMP can be used to query devices for the values of counters they keep. It
+is the value from those counters that we want to store in the RRD.
+
+=head2 What can I do with this tool?
+
+RRDtool originated from MRTG (Multi Router Traffic Grapher). MRTG
+started as a tiny little script for graphing the use of a university's
+connection to the Internet. MRTG was later (ab-)used as a tool for
+graphing other data sources including temperature, speed, voltage,
+number of printouts and the like.
+
+Most likely you will start to use RRDtool to store and process data
+collected via SNMP. The data will most likely be bytes (or bits)
+transfered from and to a network or a computer.  But it can also be
+used to display tidal waves, solar radiation, power consumption,
+number of visitors at an exhibition, noise levels near an airport,
+temperature on your favorite holiday location, temperature in the
+fridge and whatever you imagination can come up with.
+
+You only need a sensor to measure the data and be able to feed the
+numbers into RRDtool. RRDtool then lets you create a database, store
+data in it, retrieve that data and create graphs in PNG format for
+display on a web browser. Those PNG images are dependent on the data
+you collected and could be, for instance, an overview of the average
+network usage, or the peaks that occurred.
+
+=head2 What if I still have problems after reading this document?
 
 First of all: read it again! You may have missed something.
 If you are unable to compile the sources and you have a fairly common
 OS, it will probably not be the fault of RRDtool. There may be pre-compiled
 versions around on the Internet. If they come from trusted sources, get
 one of those.
+
 If on the other hand the program works but does not give you the
 expected results, it will be a problem with configuring it. Review
 your configuration and compare it with the examples that follow.
@@ -91,21 +94,22 @@ There is a mailing list and an archive of it. Read the list for a few
 weeks and search the archive. It is considered rude to just ask
 a question without searching the archives: your problem may already have been
 solved for somebody else!  This is true for most, if not all, mailing lists
-and not only for this particular list! Look in the documentation that
+and not only for this particular one. Look in the documentation that
 came with RRDtool for the location and usage of the list.
 
 I suggest you take a moment to subscribe to the mailing list right now
-by sending an email to E<lt>rrd-users-request@list.ee.ethz.chE<gt> with a
-subject of "subscribe". If you ever want to leave this list, you write
+by sending an email to E<lt>rrd-users-request@lists.oetiker.chE<gt> with a
+subject of "subscribe". If you ever want to leave this list, just write
 an email to the same address but now with a subject of "unsubscribe".
 
-=head2 How will you help me ?
+=head2 How will you help me?
 
 By giving you some detailed descriptions with detailed examples.
-It is assumed that following the instructions in the order presented
+I assume that following the instructions in the order presented
 will give you enough knowledge of RRDtool to experiment for yourself.
 If it doesn't work the first time, don't give up. Reread the stuff that
 you did understand, you may have missed something.
+
 By following the examples you get some hands-on experience and, even
 more important, some background information of how it works.
 
@@ -125,15 +129,16 @@ all the same: some number over some time.
 
 Assume we have a device that transfers bytes to and from the Internet.
 This device keeps a counter that starts at zero when it is turned on,
-increasing with every byte that is transfered. This counter will have
-a maximum value, if that value is reached and an extra byte is counted,
-the counter starts all over at zero. This is the same as many counters
+increasing with every byte that is transfered. This counter will probably have
+a maximum value. If this value is reached and an extra byte is counted,
+the counter starts over at zero. This is the same as many counters
 in the world such as the mileage counter in a car.
+
 Most discussions about networking talk about bits per second so lets
 get used to that right away. Assume a byte is eight bits and start to
-think in bits not bytes. The counter, however, still counts bytes !
+think in bits not bytes. The counter, however, still counts bytes!
 In the SNMP world most of the counters are 32 bits. That means they are
-counting from 0 to 4294967295. We will use these values in the examples.
+counting from 0 to 4'294'967'295. We will use these values in the examples.
 The device, when asked, returns the current value of the counter. We
 know the time that has passes since we last asked so we now know how
 many bytes have been transfered ***on average*** per second. This is
@@ -147,7 +152,7 @@ Take the current counter, subtract the previous value from it.
 
 =item 2.
 
-Do the same with the current time and the previous time.
+Do the same with the current time and the previous time (in seconds).
 
 =item 3.
 
@@ -159,33 +164,32 @@ number of bits per second (bps).
 
   bps = (counter_now - counter_before) / (time_now - time_before) * 8
 
-For some people it may help to translate this to a automobile example:
-Do not try this example, and if you do, don't blame me for the results.
+For some people it may help to translate this to an automobile example.
+Do not try this example, and if you do, don't blame me for the results!
 
 People who are not used to think in kilometers per hour can translate
 most into miles per hour by dividing km by 1.6 (close enough).
 I will use the following abbreviations:
 
  M:    meter
- KM:   kilometer (= 1000 meters).
+ KM:   kilometer (= 1'000 meters).
  H:    hour
  S:    second
  KM/H: kilometers per hour
  M/S:  meters per second
 
-You're driving a car. At 12:05 you read the counter in the dashboard
-and it tells you that the car has moved 12345 KM until that moment.
-At 12:10 you look again, it reads 12357 KM. This means you have
+You are driving a car. At 12:05 you read the counter in the dashboard
+and it tells you that the car has moved 12'345 KM until that moment.
+At 12:10 you look again, it reads 12'357 KM. This means you have
 traveled 12 KM in five minutes. A scientist would translate that
 into meters per second and this makes a nice comparison toward the
 problem of (bytes per five minutes) versus (bits per second).
 
-We traveled 12 kilometers which is 12000 meters. We did that in five
-minutes which translates into 300 seconds. Our speed is 12000M / 300S
-equals 40 M/S.
+We traveled 12 kilometers which is 12'000 meters. We did that in five
+minutes or 300 seconds. Our speed is 12'000M / 300S or 40 M/S.
 
-We could also calculate the speed in KM/H: 12 times five minutes
-is an hour so we have to multiply 12 KM by 12 to get 144 KM/H.
+We could also calculate the speed in KM/H: 12 times 5 minutes
+is an hour, so we have to multiply 12 KM by 12 to get 144 KM/H.
 For our native English speaking friends: that's 90 MPH so don't
 try this example at home or where I live :)
 
@@ -195,12 +199,12 @@ later on in this tutorial that explains this.
 
 I hope you understand that there is no difference in calculating M/S or
 bps; only the way we collect the data is different. Even the K from kilo
-is the same as in networking terms k also means 1000.
+is the same as in networking terms k also means 1'000.
 
 We will now create a database where we can keep all these interesting
 numbers. The method used to start the program may differ slightly from
-OS to OS but I assume you can figure it out if it works different on
-your OS. Make sure you do not overwrite any file on your system when
+OS to OS, but I assume you can figure it out if it works different on
+your's. Make sure you do not overwrite any file on your system when
 executing the following command and type the whole line as one long
 line (I had to split it for readability)
 and skip all of the '\' characters.
@@ -213,22 +217,23 @@ and skip all of the '\' characters.
 
 (So enter: C<rrdtool create test.rrd --start 920804400 DS ...>)
 
-=head2 What has been created ?
+=head2 What has been created?
 
-We created the round robin database called test (test.rrd)
-which starts at noon the day I started (7th of march, 1999) writing
-this document. It holds one data source (DS) named "speed" that gets
-built from a counter. This counter is read every five minutes (default)
-In the same database two round robin archives (RRAs) are kept, one
-averages the data every time it is read (e.g., there's nothing to average)
-and keeps 24 samples (24 times 5 minutes is 2 hours). The other averages
-6 values (half hour) and contains 10 of such averages (e.g., 5 hours)
-The remaining options will be discussed later on.
+We created the round robin database called test (test.rrd) which
+starts at noon the day I started writing this document, 7th of March,
+1999 (this date translates to 920'804'400 seconds as explained
+below). Our database holds one data source (DS) named "speed" that
+represents a counter. This counter is read every five minutes
+(default).  In the same database two round robin archives (RRAs) are
+kept, one averages the data every time it is read (e.g., there's
+nothing to average) and keeps 24 samples (24 times 5 minutes is 2
+hours). The other averages 6 values (half hour) and contains 10
+such averages (e.g., 5 hours).
 
 RRDtool works with special time stamps coming from the UNIX world.
 This time stamp is the number of seconds that passed since January
-1st 1970 UTC.  This time stamp is translated into local time and
-it will therefore look different for the different time zones.
+1st 1970 UTC.  The time stamp value is translated into local time and
+it will therefore look different for different time zones.
 
 Chances are that you are not in the same part of the world as I am.
 This means your time zone is different. In all examples where I talk
@@ -272,7 +277,7 @@ etcetera.
 
 As you can see, it is possible to feed more than one value into the
 database in one command. I had to stop at three for readability but
-the real maximum is OS dependent.
+the real maximum per line is OS dependent.
 
 We can now retrieve the data from our database using "rrdtool fetch":
 
@@ -280,35 +285,40 @@ We can now retrieve the data from our database using "rrdtool fetch":
 
 It should return the following output:
 
-                speed
-
- 920804700:       NaN
- 920805000:      0.04
- 920805300:      0.02
- 920805600:      0.00
- 920805900:      0.00
- 920806200:      0.03
- 920806500:      0.03
- 920806800:      0.03
- 920807100:      0.02
- 920807400:      0.02
- 920807700:      0.02
- 920808000:      0.01
- 920808300:      0.02
- 920808600:      0.01
- 920808900:      0.00
- 920809200:       NaN
+                          speed
+
+ 920804700: nan
+ 920805000: 4.0000000000e-02
+ 920805300: 2.0000000000e-02
+ 920805600: 0.0000000000e+00
+ 920805900: 0.0000000000e+00
+ 920806200: 3.3333333333e-02
+ 920806500: 3.3333333333e-02
+ 920806800: 3.3333333333e-02
+ 920807100: 2.0000000000e-02
+ 920807400: 2.0000000000e-02
+ 920807700: 2.0000000000e-02
+ 920808000: 1.3333333333e-02
+ 920808300: 1.6666666667e-02
+ 920808600: 6.6666666667e-03
+ 920808900: 3.3333333333e-03
+ 920809200: nan
 
 If it doesn't, something may be wrong.  Perhaps your OS will print
-"NaN" in a different form.  It represents "Not A Number".  If your OS
+"NaN" in a different form. "NaN" stands for "Not A Number".  If your OS
 writes "U" or "UNKN" or something similar that's okay.  If something
 else is wrong, it will probably be due to an error you made (assuming
 that my tutorial is correct of course :-). In that case: delete the
-database and try again.
+database and try again.  Sometimes things change.  This example used
+to provide numbers like "0.04" in stead of "4.00000e-02".  Those are
+really the same numbers, just written down differently.  Don't be
+alarmed if a future version of rrdtool displays a slightly different
+form of output. The examples in this document are correct for version
+1.2.0 of RRDtool.
 
-What this output represents will become clear in the rest of the tutorial.
+The meaning of the above output will become clear below.
 
-=head2 It is time to create some graphics
+=head2 Time to create some graphics
 
 Try the following command:
 
@@ -318,11 +328,13 @@ Try the following command:
          LINE2:myspeed#FF0000
 
 This will create speed.png which starts at 12:00 and ends at 13:00.
-There is a definition of variable myspeed, it is the data from RRA
-"speed" out of database "test.rrd". The line drawn is 2 pixels high,
-and comes from variable myspeed. The color is red.
-You'll notice that the start of the graph is not at 12:00 but at 12:05
-and this is because we have insufficient data to tell the average before
+There is a definition of a variable called myspeed, using the data from RRA
+"speed" out of database "test.rrd". The line drawn is 2 pixels high
+and represents the variable myspeed. The color is red (specified by
+its rgb-representation, see below).
+
+You'll notice that the start of the graph is not at 12:00 but at 12:05.
+This is because we have insufficient data to tell the average before
 that time. This will only happen when you miss some samples, this will
 not happen a lot, hopefully.
 
@@ -341,28 +353,34 @@ The "color" black is all colors off: 000000
    magenta #FF00FF     (mixed red with blue)
    gray    #555555     (one third of all components)
 
+Additionally you can add an alpha channel (transparency).  The default
+will be "FF" which means non-transparent.
+
 The PNG you just created can be displayed using your favorite image
 viewer.  Web browsers will display the PNG via the URL
-"file://the/path/to/speed.png"
+"file:///the/path/to/speed.png"
 
 =head2 Graphics with some math
 
 When looking at the image, you notice that the horizontal axis is labeled
-12:10, 12:20, 12:30, 12:40 and 12:50. The two remaining times (12:00 and
-13:00) would not be displayed nicely so they are skipped.
-The vertical axis displays the range we entered. We provided kilometers
-and when divided by 300 seconds, we get very small numbers. To be exact,
-the first value was 12 (12357-12345) and divided by 300 this makes 0.04,
-which is displayed by RRDtool as "40 m" meaning "40/1000". The "m" has
-nothing to do with meters, kilometers or millimeters! RRDtool doesn't
-know about all this, it just works with numbers and not with meters...
-
-What we did wrong was that we should have measured in meters, this would
-have been (12357000-12345000)/300 = 12000/300 = 40.
-
-Let's correct that. We could recreate our database and store the correct
-data but there is a better way: do some calculations while creating the
-png file !
+12:10, 12:20, 12:30, 12:40 and 12:50. Sometimes a label doesn't fit (12:00
+and 13:00 would be candidates) so they are skipped.
+
+The vertical axis displays the range we entered. We provided
+kilometers and when divided by 300 seconds, we get very small
+numbers. To be exact, the first value was 12 (12'357-12'345) and divided
+by 300 this makes 0.04, which is displayed by RRDtool as "40 m"
+meaning "40/1'000". The "m" (milli) has nothing to do with meters,
+kilometers or millimeters! RRDtool doesn't know about the physical
+units of our data, it just works with dimensionless numbers.
+
+If we had measured our distances in meters, this would have been
+(12'357'000-12'345'000)/300 = 12'000/300 = 40.
+
+As most people have a better feel for numbers in this range, we'll
+correct that. We could recreate our database and store the correct
+data, but there is a better way: we do some calculations while creating
+the png file!
 
    rrdtool graph speed2.png                           \
       --start 920804400 --end 920808000               \
@@ -371,31 +389,40 @@ png file !
       CDEF:realspeed=myspeed,1000,\*                  \
       LINE2:realspeed#FF0000
 
-After viewing this PNG, you notice the "m" has disappeared. This it what
-the correct result would be. Also, a label has been added to the image.
-Apart from the things mentioned above, the PNG should be the same.
+Note: Make sure not to forget the backslash \ in front of the
+multiplication operator * above. The backslash is needed to "escape"
+the * as some operating systems might interpret and expand * instead
+of passing it to the rrdtool command.
 
-The calculations are in the CDEF part and are in Reverse Polish Notation
-("RPN"). What it says is: "take the data source myspeed and the number
-1000; multiply those". Don't bother with RPN yet, it will be explained
-later on in more detail. Also, you may want to read my tutorial on CDEFs
-and Steve Rader's tutorial on RPN. But first finish this tutorial.
+After viewing this PNG, you notice the "m" (milli) has
+disappeared. This it what the correct result would be. Also, a label
+has been added to the image.  Apart from the things mentioned above,
+the PNG should look the same.
 
-Hang on! If we can multiply values with 1000, it should also be possible
+The calculations are specified in the CDEF part above and are in
+Reverse Polish Notation ("RPN"). What we requested RRDtool to do is:
+"take the data source myspeed and the number 1000; multiply
+those". Don't bother with RPN yet, it will be explained later on in
+more detail. Also, you may want to read my tutorial on CDEFs and Steve
+Rader's tutorial on RPN. But first finish this tutorial.
+
+Hang on! If we can multiply values with 1'000, it should also be possible
 to display kilometers per hour from the same data!
 
 To change a value that is measured in meters per second:
- -*- Calculate meters per hour:     value * 3600
- -*- Calculate kilometers per hour: value / 1000
- -*- Together this makes:           value * (3600/1000) == value * 3.6
+
+ Calculate meters per hour:     value * 3'600
+ Calculate kilometers per hour: value / 1'000
+ Together this makes:           value * (3'600/1'000) or value * 3.6
 
 In our example database we made a mistake and we need to compensate for
-this by multiplying with 1000. Applying that correction:
- -*- value * 3.6  *1000 == value * 3600
+this by multiplying with 1'000. Applying that correction:
+
+ value * 3.6  * 1'000 == value * 3'600
 
 Now let's create this PNG, and add some more magic ...
 
  rrdtool graph speed3.png                           \
rrdtool graph speed3.png                             \
       --start 920804400 --end 920808000               \
       --vertical-label km/h                           \
       DEF:myspeed=test.rrd:speed:AVERAGE              \
@@ -406,16 +433,21 @@ Now let's create this PNG, and add some more magic ...
       AREA:good#00FF00:"Good speed"                   \
       AREA:fast#FF0000:"Too fast"
 
-This looks much better. Speed in KM/H and even an extra line with the
-maximum allowed speed (on the road I travel at). I also changed the
-colors used to display speed and changed it from a line into an area.
+Note: here we use another means to escape the * operator by enclosing
+the whole string in double quotes.
+
+This graph looks much better. Speed is shown in KM/H and there is even
+an extra line with the maximum allowed speed (on the road I travel
+on). I also changed the colors used to display speed and changed it
+from a line into an area.
 
-The calculations are more complex now. For the "good" speed they are:
+The calculations are more complex now. For speed measurements within
+the speed limit they are:
 
    Check if kmh is greater than 100    ( kmh,100 ) GT
    If so, return 0, else kmh           ((( kmh,100 ) GT ), 0, kmh) IF
 
-For the other speed:
+For values above the speed limit:
 
    Check if kmh is greater than 100    ( kmh,100 ) GT
    If so, return kmh, else return 0    ((( kmh,100) GT ), kmh, 0) IF
@@ -439,7 +471,7 @@ following PNG:
       AREA:fast#550000:"Too fast"                     \
       STACK:over#FF0000:"Over speed"
 
-Let's create a quick and dirty HTML page to view three PNGs:
+Let's create a quick and dirty HTML page to view the three PNGs:
 
    <HTML><HEAD><TITLE>Speed</TITLE></HEAD><BODY>
    <IMG src="speed2.png" alt="Speed in meters per second">
@@ -449,68 +481,75 @@ Let's create a quick and dirty HTML page to view three PNGs:
    <IMG src="speed4.png" alt="Traveled too fast?">
    </BODY></HTML>
 
-Name the file "speed.html" or similar, and view it.
+Name the file "speed.html" or similar, and look at it in your web browser.
 
 Now, all you have to do is measure the values regularly and update the
 database.  When you want to view the data, recreate the PNGs and make
 sure to refresh them in your browser. (Note: just clicking reload may
-not be enough; Netscape in particular has a problem doing so and you'll
-need to click reload while pressing the shift key).
+not be enough, especially when proxies are involved.  Try shift-reload
+or ctrl-F5).
 
 =head2 Updates in Reality
 
-We've already used the "update" command: it took one or more parameters
-in the form of "<time>:<value>". You'll be glad to know that you can
-get the current time by filling in a "N" as the time.
-If you wish, you can also use the "time" function in perl.
-The shortest example in this doc :)
+We've already used the "update" command: it took one or more
+parameters in the form of "<time>:<value>". You'll be glad to know
+that you can specify the current time by filling in a "N" as the time.
+Or you could use the "time" function in Perl (the shortest example in
+this tutorial):
 
    perl -e 'print time, "\n" '
 
-How you can run a program on regular intervals is OS specific. But here's
+How to run a program on regular intervals is OS specific. But here is
 an example in pseudo code:
 
-   Get the value, put it in variable "$speed"
-   rrdtool update speed.rrd N:$speed
+   - Get the value and put it in variable "$speed"
+   rrdtool update speed.rrd N:$speed
 
-(Do not try this with our test database, it is used in further examples)
+(do not try this with our test database, we'll use it in further examples)
 
-This is all. Run this script every five minutes. When you need to know
-what the graphics look like, run the examples above. You could put them
-in a script. After running that script, view index.html
+This is all. Run the above script every five minutes. When you need to know
+what the graphs look like, run the examples above. You could put them
+in a script as well. After running that script, view the page
+index.html we created above.
 
 =head2 Some words on SNMP
 
-I can imagine very few people will be able to get real data from their
-car every five minutes, all other people will have to settle for some
-other kind of counter. You could measure the number of pages printed by
-a printer, the coffee made by the coffee machine, a device that counts
-the electricity used, whatever. Any incrementing counter can be monitored
-and graphed using the stuff you learned until now. Later on we will also
-be able to monitor other types of values like temperature.
-Most people will use the counter that keeps track
-of octets (bytes) transfered by a network device so we have to do just
-that. We will start with a description of how to collect data.
+I can imagine very few people that will be able to get real data from
+their car every five minutes. All other people will have to settle for
+some other kind of counter. You could measure the number of pages
+printed by a printer, for example, the cups of coffee made by the
+coffee machine, a device that counts the electricity used,
+whatever. Any incrementing counter can be monitored and graphed using
+the stuff you learned so far. Later on we will also be able to monitor
+other types of values like temperature.
+
+Most (?) people interested in RRDtool will use the counter that keeps track
+of octets (bytes) transfered by a network device. So let's do just
+that next. We will start with a description of how to collect data.
+
 Some people will make a remark that there are tools which can do this data
-collection for you. They are right!  However, I feel it is important that
-you understand they are not necessary.  When you have to determine why
+collection for you. They are right! However, I feel it is important that
+you understand they are not necessary. When you have to determine why
 things went wrong you need to know how they work.
 
 One tool used in the example has been talked about very briefly in the
-beginning of this document, it is called SNMP. It is a way of talking to
-equipment. The tool I use below is called "snmpget" and this is how it
-works:
+beginning of this document, it is called SNMP. It is a way of talking
+to networked equipment. The tool I use below is called "snmpget" and
+this is how it works:
 
    snmpget device password OID
 
+or
+
+   snmpget -v[version] -c[password] device OID
+
 For device you substitute the name, or the IP address, of your device.
 For password you use the "community read string" as it is called in the
 SNMP world.  For some devices the default of "public" might work, however
 this can be disabled, altered or protected for privacy and security
 reasons.  Read the documentation that comes with your device or program.
 
-Then there is this third parameter, called OID, which means "object
-identifier".
+Then there is this parameter, called OID, which means "object identifier".
 
 When you start to learn about SNMP it looks very confusing. It isn't
 all that difficult when you look at the Management Information Base
@@ -525,49 +564,47 @@ These names can also be written down as numbers and are 1 3 6 1 2 1.
 
 There is a lot of confusion about the leading dot that some programs
 use.  There is *no* leading dot in an OID.  However, some programs
-can use above part of OIDs as a default.  To indicate the difference
+can use the above part of OIDs as a default.  To indicate the difference
 between abbreviated OIDs and full OIDs they need a leading dot when
 you specify the complete OID.  Often those programs will leave out
 the default portion when returning the data to you.  To make things
 worse, they have several default prefixes ...
 
-Right, lets continue to the start of our OID: we had 1.3.6.1.2.1
+Ok, lets continue to the start of our OID: we had 1.3.6.1.2.1
 From there, we are especially interested in the branch "interfaces"
 which has number 2 (e.g., 1.3.6.1.2.1.2 or 1.3.6.1.2.1.interfaces).
 
 First, we have to get some SNMP program. First look if there is a
 pre-compiled package available for your OS. This is the preferred way.
-If not, you will have to get yourself the sources and compile those.
+If not, you will have to get the sources yourself and compile those.
 The Internet is full of sources, programs etc. Find information using
-a search engine or whatever you prefer. As a suggestion: look for
-CMU-SNMP.  It is commonly used.
+a search engine or whatever you prefer.
 
 Assume you got the program. First try to collect some data that is
 available on most systems. Remember: there is a short name for the
 part of the tree that interests us most in the world we live in!
 
-I will use the short version as I think this document is large enough
-as it is. If that doesn't work for you, prefix with .1.3.6.1.2.1 and
-try again.  Also, Read The Fine Manual.  Skip the parts you cannot
-understand yet, you should be able to find out how to start the
-program and use it.
+I will give an example which can be used on Fedora Core 3.  If it
+doesn't work for you, work your way through the manual of snmp and
+adapt the example to make it work.
 
-   snmpget myrouter public system.sysDescr.0
+   snmpget -v2c -c public myrouter system.sysDescr.0
 
-The device should answer with a description of itself, perhaps empty.
-Until you got a valid answer from a device, perhaps using a different
-"password", or a different device, there is no point in continuing.
+The device should answer with a description of itself, perhaps an
+empty one. Until you got a valid answer from a device, perhaps using a
+different "password", or a different device, there is no point in
+continuing.
 
-   snmpget myrouter public interfaces.ifNumber.0
+   snmpget -v2c -c public myrouter interfaces.ifNumber.0
 
 Hopefully you get a number as a result, the number of interfaces.
 If so, you can carry on and try a different program called "snmpwalk".
 
-   snmpwalk myrouter public interfaces.ifTable.ifEntry.ifDescr
+   snmpwalk -v2c -c public myrouter interfaces.ifTable.ifEntry.ifDescr
 
 If it returns with a list of interfaces, you're almost there.
 Here's an example:
-   [user@host /home/alex]$ snmpwalk cisco public 2.2.1.2
+   [user@host /home/alex]$ snmpwalk -v2c -c public cisco 2.2.1.2
 
    interfaces.ifTable.ifEntry.ifDescr.1 = "BRI0: B-Channel 1"
    interfaces.ifTable.ifEntry.ifDescr.2 = "BRI0: B-Channel 2"
@@ -576,9 +613,9 @@ Here's an example:
    interfaces.ifTable.ifEntry.ifDescr.5 = "Loopback0"
 
 On this cisco equipment, I would like to monitor the "Ethernet0"
-interface and see that it is number four. I try:
+interface and from the above output I see that it is number four. I try:
 
-   [user@host /home/alex]$ snmpget cisco public 2.2.1.10.4 2.2.1.16.4
+   [user@host /home/alex]$ snmpget -v2c -c public cisco 2.2.1.10.4 2.2.1.16.4
 
    interfaces.ifTable.ifEntry.ifInOctets.4 = 2290729126
    interfaces.ifTable.ifEntry.ifOutOctets.4 = 1256486519
@@ -594,13 +631,13 @@ and
 both with an interface number of 4.
 
 Don't get fooled, this wasn't my first try. It took some time for me too
-to understand what all these numbers mean, it does help a lot when they
+to understand what all these numbers mean. It does help a lot when they
 get translated into descriptive text... At least, when people are talking
 about MIBs and OIDs you know what it's all about.
 Do not forget the interface number (0 if it is not interface dependent)
 and try snmpwalk if you don't get an answer from snmpget.
 
-If you understand above part, and get numbers from your device, continue
+If you understand the above section and get numbers from your device, continue
 on with this tutorial. If not, then go back and re-read this part.
 
 =head2 A Real World Example
@@ -617,19 +654,19 @@ starting point, which is the same as five minutes.
  24 samples averaged become one average on 2 hours
  288 samples averaged become one average on 1 day
 
-Lets try to be compatible with MRTG:
-MRTG stores about the following amount of data:
+Lets try to be compatible with MRTG which stores about the following
+amount of data:
 
  600 5-minute samples:    2   days and 2 hours
  600 30-minute samples:  12.5 days
  600 2-hour samples:     50   days
  732 1-day samples:     732   days
 
-These ranges are appended so the total amount of data kept is approximately
-797 days.  RRDtool stores the data differently, it doesn't start the "weekly"
-archive where the "daily" archive stopped.  For both archives the most recent
-data will be near "now" and therefore we will need to keep more data than
-MRTG does!
+These ranges are appended, so the total amount of data stored in the
+database is approximately 797 days. RRDtool stores the data
+differently, it doesn't start the "weekly" archive where the "daily"
+archive stopped. For both archives the most recent data will be near
+"now" and therefore we will need to keep more data than MRTG does!
 
 We will need:
 
@@ -650,8 +687,8 @@ We will need:
             RRA:MAX:0.5:24:775         \
             RRA:MAX:0.5:288:797
 
-Next thing to do is collect data and store it. Here is an example.
-It is written partially in pseudo code so you will have to find out what
+Next thing to do is to collect data and store it. Here is an example.
+It is written partially in pseudo code you will have to find out what
 to do exactly on your OS to make it work.
 
    while not the end of the universe
@@ -677,19 +714,18 @@ Then, after collecting data for a day, try to create an image using:
             LINE1:outoctets#0000FF:"Out traffic"
 
 This should produce a picture with one day worth of traffic.
-One day is 24 hours of 60 minutes of 60 seconds: 24*60*60=86400, we
-start at now minus 86400 seconds. We define (with DEFs) inoctets and
+One day is 24 hours of 60 minutes of 60 seconds: 24*60*60=86'400, we
+start at now minus 86'400 seconds. We define (with DEFs) inoctets and
 outoctets as the average values from the database myrouter.rrd and draw
 an area for the "in" traffic and a line for the "out" traffic.
 
 View the image and keep logging data for a few more days.
 If you like, you could try the examples from the test database and
-see if you can get various options and calculations working.
-
-Suggestion:
+see if you can get various options and calculations to work.
 
-Display in bytes per second and in bits per second. Make the Ethernet
-graphics go red if they are over four megabits per second.
+Suggestion: Display in bytes per second and in bits per second. Make
+the Ethernet graphics go red if they are over four megabits per
+second.
 
 =head2 Consolidation Functions
 
@@ -697,21 +733,20 @@ A few paragraphs back I mentioned the possibility of keeping
 the maximum values instead of the average values. Let's go
 into this a bit more.
 
-
 Recall all the stuff about the speed of the car. Suppose we drove at 144
 KM/H during 5 minutes and then were stopped by the police for 25 minutes.
-At the end of the lecture we would take our laptop and create+view the
+At the end of the lecture we would take our laptop and create and view the
 image taken from the database. If we look at the second RRA we did
 create, we would have the average from 6 samples. The samples measured
 would be 144+0+0+0+0+0=144, divided by 30 minutes, corrected for the
 error by 1000, translated into KM/H, with a result of 24 KM/H.
 I would still get a ticket but not for speeding anymore :)
 
-Obviously, in this case, we shouldn't look at the averages. In some
-cases they are handy. If you want to know how much KM you had traveled,
-the picture would be the right one to look at. On the other hand, for
-the speed that we traveled at, the maximum number seen is much more
-valuable. (later we will see more types)
+Obviously, in this case we shouldn't look at the averages. In some
+cases they are handy. If you want to know how many KM you had traveled,
+the averaged picture would be the right one to look at. On the other hand, for
+the speed that we traveled at, the maximum numbers seen is much more
+interesting. Later we will see more types.
 
 It is the same for data. If you want to know the amount, look at the
 averages. If you want to know the rate, look at the maximum.
@@ -719,9 +754,10 @@ Over time, they will grow apart more and more. In the last database
 we have created, there are two archives that keep data per day. The
 archive that keeps averages will show low numbers, the archive that
 shows maxima will have higher numbers.
+
 For my car this would translate in averages per day of 96/24=4 KM/H
-(as I travel about 94 kilometers on a day) during week days, and
-maximum of 120 KM/H on weekdays (my top speed that I reach every day).
+(as I travel about 94 kilometers on a day) during working days, and
+maxima of 120 KM/H (my top speed that I reach every day).
 
 Big difference. Do not look at the second graph to estimate the
 distances that I travel and do not look at the first graph to
@@ -729,11 +765,12 @@ estimate my speed. This will work if the samples are close together,
 as they are in five minutes, but not if you average.
 
 On some days, I go for a long ride. If I go across Europe and travel
-for over 12 hours, the first graph will rise to about 60 KM/H. The
-second one will show 180 KM/H. This means that I traveled a distance
-of 60 KM/H times 24 H = 1440 KM. I did this with a higher speed and
-a maximum around 180 KM/H. This doesn't mean that I traveled for 8
-hours at a constant speed of 180 KM/H !
+for 12 hours, the first graph will rise to about 60 KM/H. The second
+one will show 180 KM/H. This means that I traveled a distance of 60
+KM/H times 24 H = 1440 KM. I did this with a higher speed and a
+maximum around 180 KM/H. However, it probably doesn't mean that I
+traveled for 8 hours at a constant speed of 180 KM/H!
+
 This is a real example: go with the flow through Germany (fast!) and stop
 a few times for gas and coffee. Drive slowly through Austria and the
 Netherlands. Be careful in the mountains and villages. If you would
@@ -743,38 +780,38 @@ average and maximum graphs (provided I measured every 300 seconds).
 You would be able to see when I stopped, when I was in top gear, when
 I drove over fast highways etc. The granularity of the data is much
 higher, so you can see more. However, this takes 12 samples per hour,
-or 288 values per day, so it would be too much to keep for a long
+or 288 values per day, so it would be a lot of data over a longer
 period of time. Therefore we average it, eventually to one value per
-day. From this one value, we cannot see much detail.
+day. From this one value, we cannot see much detail, of course.
 
 Make sure you understand the last few paragraphs. There is no value
 in only a line and a few axis, you need to know what they mean and
-interpret the data in a good way. This is true for all data.
+interpret the data in ana appropriate way. This is true for all data.
 
 The biggest mistake you can make is to use the collected data for
 something that it is not suitable for. You would be better off if
-you would not have the graphics at all in that case.
+you didn't have the graph at all.
 
 
-=head2 Let's review what you now should know.
+=head2 Let's review what you now should know
 
-You now know how to create a database. You can put the numbers in it,
-get them out again by creating an image, do math on the data from the
-database and view the outcome instead of the raw data.
-You know about the difference between averages and maxima, and when
-to use which (or at least you have an idea).
+You know how to create a database and can put data in it. You can get
+the numbers out again by creating an image, do math on the data from
+the database and view the resulte instead of the raw data.  You know
+about the difference between averages and maxima, and when to use
+which (or at least you should have an idea).
 
 RRDtool can do more than what we have learned up to now. Before you
 continue with the rest of this doc, I recommend that you reread from
 the start and try some modifications on the examples. Make sure you
 fully understand everything. It will be worth the effort and helps
-you not only with the rest of this doc but also in your day to day
+you not only with the rest of this tutorial, but also in your day to day
 monitoring long after you read this introduction.
 
 =head2 Data Source Types
 
 All right, you feel like continuing. Welcome back and get ready
-for an increased speed in the examples and explanation.
+for an increased speed in the examples and explanations.
 
 You know that in order to view a counter over time, you have to
 take two numbers and divide the difference of them between the
@@ -784,16 +821,16 @@ temperature from my router in three places namely the inlet, the
 so called hot-spot and the exhaust.  These values are not counters.
 If I take the difference of the two samples and divide that by
 300 seconds I would be asking for the temperature change per second.
-Hopefully this is zero! If not, the computer room is on fire :)
+Hopefully this is zero! If not, the computer room is probably on fire :)
 
-So, what can we do ?  We can tell RRDtool to store the values we measure
+So, what can we do?  We can tell RRDtool to store the values we measure
 directly as they are (this is not entirely true but close enough). The
 graphs we make will look much better, they will show a rather constant
 value. I know when the router is busy (it
 works -> it uses more electricity -> it generates more heat -> the
 temperature rises). I know when the doors are left open (the room is
-cooled -> the warm air from the rest of the building flows into the
-computer room -> the inlet temperature rises) etc. The data type we
+air conditioned) -> the warm air from the rest of the building flows into the
+computer room -> the inlet temperature rises). Etc. The data type we
 use when creating the database before was counter, we now have a
 different data type and thus a different name for it. It is called
 GAUGE. There are more such data types:
@@ -803,11 +840,11 @@ GAUGE. There are more such data types:
  - DERIVE
  - ABSOLUTE
 
-The two new types are DERIVE and ABSOLUTE. Absolute can be used like
+The two additional types are DERIVE and ABSOLUTE. Absolute can be used like
 counter with one difference: RRDtool assumes the counter is reset when
 it's read. That is: its delta is known without calculation by RRDtool
 whereas RRDtool needs to calculate it for the counter type.
-Example: our first example (12345, 12357, 12363, 12363) would read:
+Example: our first example (12'345, 12'357, 12'363, 12'363) would read:
 unknown, 12, 6, 0. The rest of the calculations stay the same.
 The other one, derive, is like counter. Unlike counter, it can also
 decrease so it can have a negative delta. Again, the rest of the
@@ -844,8 +881,8 @@ Let's try them all:
 
 =item *
 
-Line A is a counter so it should continuously increment and RRDtool
-should calculate the differences. Also, RRDtool needs to divide the
+Line A is a COUNTER type, so it should continuously increment and RRDtool
+must calculate the differences. Also, RRDtool needs to divide the
 difference by the amount of time lapsed. This should end up as a
 straight line at 1 (the deltas are 300, the time is 300).
 
@@ -856,28 +893,29 @@ what we put in: a sort of a wave.
 
 =item *
 
-Line C is derive. It should be a counter that can decrease. It does
-so between 2400 and 0, with 1800 in-between.
+Line C is of type DERIVE. It should be a counter that can decrease. It does
+so between 2'400 and 0, with 1'800 in-between.
 
 =item *
 
-Line D is of type absolute. This is like counter but it works on
+Line D is of type ABSOLUTE. This is like counter but it works on
 values without calculating the difference. The numbers are the same
 and as you can see (hopefully) this has a different result.
 
 =back
 
 This translates in the following values, starting at 23:10 and ending
-at 00:10 the next day (where U means unknown/unplotted):
+at 00:10 the next day (where "u" means unknown/unplotted):
 
  - Line A:  u  u  1  1  1  1  1  1  1  1  1  u
  - Line B:  u  1  3  5  3  1  2  4  6  4  2  u
  - Line C:  u  u  2  2  2  0 -2 -6  2  0  2  u
  - Line D:  u  1  2  3  4  5  6  7  8  9 10  u
 
-If your PNG shows all this, you know you have typed the data correct,
-the RRDtool executable is working properly, your viewer doesn't fool you
+If your PNG shows all this, you know you have entered the data correctly,
+the RRDtool executable is working properly, your viewer doesn't fool you,
 and you successfully entered the year 2000 :)
+
 You could try the same example four times, each time with only one of
 the lines.
 
@@ -888,34 +926,35 @@ Let's go over the data again:
 =item *
 
 Line A: 300,600,900 and so on. The counter delta is a constant 300 and
-so it the time delta. A number divided by itself is always 1 (except
+so is the time delta. A number divided by itself is always 1 (except
 when dividing by zero which is undefined/illegal).
-Why is it that the first point is unknown ? We do know what we put into
-the database ? True ! But we didn't have a value to calculate the delta
-from so we don't know where we started. It would be wrong to assume we
-started at zero so we don't !
+
+Why is it that the first point is unknown? We do know what we put into
+the database, right? True, But we didn't have a value to calculate the delta
+from, so we don't know where we started. It would be wrong to assume we
+started at zero so we don't!
 
 =item *
 
-Line B: There is nothing to calculate. The numbers are as is.
+Line B: There is nothing to calculate. The numbers are as they are.
 
 =item *
 
-Line C: Again, the start-out value is unknown. The same story is valid
-like for line A. In this case the deltas are not constant so the line
-is not. If we would put the same numbers in the database as we did for
+Line C: Again, the start-out value is unknown. The same story is holds
+as for line A. In this case the deltas are not constant, therefore the line
+is not either. If we would put the same numbers in the database as we did for
 line A, we would have gotten the same line. Unlike type counter,
 this type can decrease and I hope to show you later on why
-there is a difference.
+this makes a difference.
 
 =item *
 
 Line D: Here the device calculates the deltas. Therefore we DO know the
-first delta and it is plotted. We had the same input as with line A but
-the meaning of this input is different. Therefore the line is different.
+first delta and it is plotted. We had the same input as with line A, but
+the meaning of this input is different and thus the line is different.
 In this case the deltas increase each time with 300. The time delta
 stays at a constant 300 and therefore the division of the two gives
-increasing results.
+increasing values.
 
 =back
 
@@ -923,29 +962,29 @@ increasing results.
 
 There are a few more basics to show. Some important options are still to
 be covered and we haven't look at counter wraps yet. First the counter wrap:
-In our car we notice that our counter shows 999987. We travel 20 KM and
-the counter should go to 1000007. Unfortunately, there are only six digits
-on our counter so it really shows 000007. If we would plot that on a type
-DERIVE, it would mean that the counter was set back 999980 KM. It wasn't,
+In our car we notice that the counter shows 999'987. We travel 20 KM and
+the counter should go to 1'000'007. Unfortunately, there are only six digits
+on our counter so it really shows 000'007. If we would plot that on a type
+DERIVE, it would mean that the counter was set back 999'980 KM. It wasn't,
 and there has to be some protection for this. This protection is only
 available for type COUNTER which should be used for this kind of counter
-anyways. How does it work ? Type counter should never decrease and
-therefore RRDtool must assume it wrapped if it does decrease !
+anyways. How does it work? Type counter should never decrease and
+therefore RRDtool must assume it wrapped if it does decrease!
 If the delta is negative, this can be compensated for by adding the
 maximum value of the counter + 1. For our car this would be:
 
- Delta = 7 - 999987 = -999980    (instead of 1000007-999987=20)
+ Delta = 7 - 999'987 = -999'980    (instead of 1'000'007-999'987=20)
 
- Real delta = -999980 + 999999 + 1 = 20
+ Real delta = -999'980 + 999'999 + 1 = 20
 
 At the time of writing this document, RRDtool knows of counters that
 are either 32 bits or 64 bits of size. These counters can handle the
 following different values:
 
- - 32 bits: 0 ..           4294967295
- - 64 bits: 0 .. 18446744073709551615
+ - 32 bits: 0 ..           4'294'967'295
+ - 64 bits: 0 .. 18'446'744'073'709'551'615
 
-If these numbers look strange to you, you would like to view them in
+If these numbers look strange to you, you can view them in
 their hexadecimal form:
 
  - 32 bits: 0 ..         FFFFFFFF
@@ -955,15 +994,16 @@ RRDtool handles both counters the same. If an overflow occurs and
 the delta would be negative, RRDtool first adds the maximum of a small
 counter + 1 to the delta. If the delta is still negative, it had to be
 the large counter that wrapped. Add the maximum possible value of the
-large counter + 1 and subtract the falsely added small value.
+large counter + 1 and subtract the erroneously added small value.
+
 There is a risk in this: suppose the large counter wrapped while adding
-a huge delta, it could happen in theory that adding the smaller value
+a huge delta, it could happen, theoretically, that adding the smaller value
 would make the delta positive. In this unlikely case the results would
 not be correct. The increase should be nearly as high as the maximum
-counter value for that to happen so chances are you would have several
+counter value for that to happen, so chances are you would have several
 other problems as well and this particular problem would not even be
-worth thinking about. Even though I did include an example of it so you
-can judge that for yourself.
+worth thinking about. Even though, I did include an example, so you
+can judge for yourself.
 
 The next section gives you some numerical examples for counter-wraps.
 Try to do the calculations yourself or just believe me if your calculator
@@ -971,78 +1011,83 @@ can't handle the numbers :)
 
 Correction numbers:
 
- - 32 bits: (4294967295+1) =                                 4294967296
- - 64 bits: (18446744073709551615+1)-correction1 = 18446744069414584320
-
- Before:        4294967200
- Increase:             100
- Should become: 4294967300
- But really is:          4
- Delta:        -4294967196
- Correction1:  -4294967196 +4294967296 = 100
-
- Before:        18446744073709551000
- Increase:                       800
- Should become: 18446744073709551800
- But really is:                  184
- Delta:        -18446744073709550816
- Correction1:  -18446744073709550816 +4294967296 = -18446744069414583520
- Correction2:  -18446744069414583520 +18446744069414584320 = 800
-
- Before:        18446744073709551615 ( maximum value )
- Increase:      18446744069414584320 ( absurd increase, minimum for
- Should become: 36893488143124135935             this example to work )
- But really is: 18446744069414584319
- Delta:                  -4294967296
- Correction1:  -4294967296 + 4294967296 = 0
+ - 32 bits: (4'294'967'295 + 1) =                                4'294'967'296
+ - 64 bits: (18'446'744'073'709'551'615 + 1)
+                                   - correction1 = 18'446'744'069'414'584'320
+
+ Before:        4'294'967'200
+ Increase:                100
+ Should become: 4'294'967'300
+ But really is:             4
+ Delta:        -4'294'967'196
+ Correction1:  -4'294'967'196 + 4'294'967'296 = 100
+
+ Before:        18'446'744'073'709'551'000
+ Increase:                             800
+ Should become: 18'446'744'073'709'551'800
+ But really is:                        184
+ Delta:        -18'446'744'073'709'550'816
+ Correction1:  -18'446'744'073'709'550'816
+                               + 4'294'967'296 = -18'446'744'069'414'583'520
+ Correction2:  -18'446'744'069'414'583'520
+                  + 18'446'744'069'414'584'320 = 800
+
+ Before:        18'446'744'073'709'551'615 ( maximum value )
+ Increase:      18'446'744'069'414'584'320 ( absurd increase, minimum for
+ Should become: 36'893'488'143'124'135'935             this example to work )
+ But really is: 18'446'744'069'414'584'319
+ Delta:                     -4'294'967'296
+ Correction1:  -4'294'967'296 + 4'294'967'296 = 0
  (not negative -> no correction2)
 
- Before:        18446744073709551615 ( maximum value )
- Increase:      18446744069414584319 ( one less increase )
- Should become: 36893488143124135934
- But really is: 18446744069414584318
- Delta:                  -4294967297
- Correction1:  -4294967297 +4294967296 = -1
- Correction2:  -1 +18446744069414584320 = 18446744069414584319
+ Before:        18'446'744'073'709'551'615 ( maximum value )
+ Increase:      18'446'744'069'414'584'319 ( one less increase )
+ Should become: 36'893'488'143'124'135'934
+ But really is: 18'446'744'069'414'584'318
+ Delta:                     -4'294'967'297
+ Correction1:  -4'294'967'297 + 4'294'967'296 = -1
+ Correction2:  -1 + 18'446'744'069'414'584'320 = 18'446'744'069'414'584'319
 
 As you can see from the last two examples, you need strange numbers
-for RRDtool to fail (provided it's bug free of course) so this should
-not happen.  However, SNMP or whatever method you choose to collect the
-data might also report wrong numbers occasionally.  We can't prevent all
-errors but there are some things we can do.  The RRDtool "create" command
+for RRDtool to fail (provided it's bug free of course), so this should
+not happen. However, SNMP or whatever method you choose to collect the
+data, might also report wrong numbers occasionally.  We can't prevent all
+errors, but there are some things we can do. The RRDtool "create" command
 takes two special parameters for this. They define
-the minimum and maximum allowed value. Until now, we used "U", meaning
+the minimum and maximum allowed values. Until now, we used "U", meaning
 "unknown". If you provide values for one or both of them and if RRDtool
-receives values that are outside these limits, it will ignore those
+receives data points that are outside these limits, it will ignore those
 values. For a thermometer in degrees Celsius, the absolute minimum is
 just under -273. For my router, I can assume this minimum is much higher
-so I would say it is 10. The maximum temperature for my router I would
-state as 80. Any higher and the device would be out of order.
-For my car, I would never expect negative numbers and also I would not
-expect numbers to be higher than 230. Anything else, and there must have
-been an error. Remember: the opposite is not true, if the numbers pass
-this check it doesn't mean that they are correct. Always judge the
-graph with a healthy dose of paranoia if it looks weird.
+so I would set it to 10, where as the maximum temperature I would
+set to 80. Any higher and the device would be out of order.
+
+For the speed of my car, I would never expect negative numbers and
+also I would not expect a speed  higher than 230. Anything else,
+and there must have been an error. Remember: the opposite is not true,
+if the numbers pass this check, it doesn't mean that they are
+correct. Always judge the graph with a healthy dose of suspicion if it
+seems weird to you.
 
 =head2 Data Resampling
 
-One important feature of RRDtool has not been explained yet:
-It is virtually impossible to collect the data and feed it into RRDtool
-on exact intervals. RRDtool therefore interpolates the data so it is on
-exact intervals. If you do not know what this means or how it works,
-then here's the help you seek:
+One important feature of RRDtool has not been explained yet: it is
+virtually impossible to collect data and feed it into RRDtool on exact
+intervals. RRDtool therefore interpolates the data, so they are stored
+on exact intervals. If you do not know what this means or how it
+works, then here's the help you seek:
 
-Suppose a counter increases with exactly one for every second. You want
+Suppose a counter increases by exactly one for every second. You want
 to measure it in 300 seconds intervals. You should retrieve values
 that are exactly 300 apart. However, due to various circumstances you
 are a few seconds late and the interval is 303. The delta will also be
-303 in that case. Obviously RRDtool should not put 303 in the database
-and make you believe that the counter increased 303 in 300 seconds.
+303 in that case. Obviously, RRDtool should not put 303 in the database
+and make you believe that the counter increased by 303 in 300 seconds.
 This is where RRDtool interpolates: it alters the 303 value as if it
 would have been stored earlier and it will be 300 in 300 seconds.
 Next time you are at exactly the right time. This means that the current
-interval is 297 seconds and also the counter increased with 297. Again
-RRDtool alters the value and stores 300 as it should be.
+interval is 297 seconds and also the counter increased by 297. Again,
+RRDtool interpolates and stores 300 as it should be.
 
       in the RRD                 in reality
 
@@ -1051,23 +1096,29 @@ RRDtool alters the value and stores 300 as it should be.
  time+600: 600 delta=300   time+603:  603 delta=303
  time+900: 900 delta=300   time+900:  900 delta=297
 
-Let's create two identical databases. I've chosen the time range 920805000
-to 920805900 as this goes very well with the example numbers.
+Let's create two identical databases. I've chosen the time range 920'805'000
+to 920'805'900 as this goes very well with the example numbers.
 
    rrdtool create seconds1.rrd   \
       --start 920804700          \
       DS:seconds:COUNTER:600:U:U \
       RRA:AVERAGE:0.5:1:24
 
+Make a copy
+
    for Unix: cp seconds1.rrd seconds2.rrd
    for Dos:  copy seconds1.rrd seconds2.rrd
    for vms:  how would I know :)
 
+Put in some data
+
    rrdtool update seconds1.rrd \
       920805000:000 920805300:300 920805600:600 920805900:900
    rrdtool update seconds2.rrd \
       920805000:000 920805300:300 920805603:603 920805900:900
 
+Create output
+
    rrdtool graph seconds1.png                       \
       --start 920804700 --end 920806200             \
       --height 200                                  \
@@ -1085,27 +1136,30 @@ to 920805900 as this goes very well with the example numbers.
       LINE2:seconds#0000FF                          \
       AREA:unknown#FF0000
 
-Both graphs should show the same.
+View both images together (add them to your index.html file)
+and compare. Both graphs should show the same, despite the
+input being different.
 
 =head1 WRAPUP
 
-It's time to wrap up this document. You now know all the basics to be
-able to work with RRDtool and to read the documentation available.
-There is plenty more to discover about RRDtool and you will find more and
-more uses for the package. You could create easy graphics using just the
-examples provided and using only RRDtool. You could also use the front
-ends that are available.
+It's time now to wrap up this tutorial. We covered all the basics for
+you to be able to work with RRDtool and to read the additional
+documentation available. There is plenty more to discover about
+RRDtool and you will find more and more uses for this package. You can
+easly create graphs using just the examples provided and using only
+RRDtool. You can also use one of the front ends to RRDtool that are
+available.
 
 =head1 MAILINGLIST
 
-Remember to subscribe to the mailing-list. Even if you are not answering
-the mails that come by, it helps both you and the rest. A lot of the stuff
-that I know about MRTG (and therefore about RRDtool) I've learned while
-just reading the list without posting to it. I did not need to ask the
-basic questions as they are answered in the FAQ (read it!) and
-in various mails by other users.
-With thousands of users all over the world, there will always be people
-who ask questions that you can answer because you read this and other
+Remember to subscribe to the RRDtool mailing list. Even if you are not
+answering to mails that come by, it helps both you and the rest of the
+users. A lot of the stuff that I know about MRTG (and therefore about
+RRDtool) I've learned while just reading the list without posting to
+it. I did not need to ask the basic questions as they are answered in
+the FAQ (read it!) and in various mails by other users. With
+thousands of users all over the world, there will always be people who
+ask questions that you can answer because you read this and other
 documentation and they didn't.
 
 =head1 SEE ALSO
@@ -1116,7 +1170,7 @@ The RRDtool manpages
 
 I hope you enjoyed the examples and their descriptions. If you do, help
 other people by pointing them to this document when they are asking
-basic questions. They will not only get their answer but at the same
+basic questions. They will not only get their answers, but at the same
 time learn a whole lot more.
 
 Alex van den Bogaerdt
index 2d4ee8c7dd4d94dfe7336f205dce1f00cacc5091..cc0b452f76ce0e9faeb3d6cbd54058f5fa86f40f 100644 (file)
@@ -1,22 +1,20 @@
 =head1 NAME
 
-rrdtool update - Store a new set of values into the RRD
-
-=for html <div align="right"><a href="rrdupdate.pdf">PDF</a> version.</div>
+rrdupdate - Store a new set of values into the RRD
 
 =head1 SYNOPSIS
 
-B<rrdtool> {B<update> | B<updatev>} I<filename> 
-S<[B<--template>|B<-t> I<ds-name>[B<:>I<ds-name>]...]> 
-S<B<N>|I<timestamp>B<:>I<value>[B<:>I<value>...]> 
-S<I<at-timestamp>B<@>I<value>[B<:>I<value>...]> 
+B<rrdtool> {B<update> | B<updatev>} I<filename>
+S<[B<--template>|B<-t> I<ds-name>[B<:>I<ds-name>]...]>
+S<B<N>|I<timestamp>B<:>I<value>[B<:>I<value>...]>
+S<I<at-timestamp>B<@>I<value>[B<:>I<value>...]>
 S<[I<timestamp>B<:>I<value>[B<:>I<value>...] ...]>
 
 =head1 DESCRIPTION
 
-The B<update> function feeds new data values into an B<RRD>. The
-data gets time aligned according to the properties of the B<RRD> to
-which the data is written.
+The B<update> function feeds new data values into an B<RRD>. The data
+is time aligned (interpolated) according to the properties of the
+B<RRD> to which the data is written.
 
 =over 8
 
@@ -37,11 +35,12 @@ The name of the B<RRD> you want to update.
 
 =item B<--template>|B<-t> I<ds-name>[B<:>I<ds-name>]...
 
-by default, the B<update> function expects the data input in the order
-the data sources are defined in the RRD, excluding any COMPUTE data sources 
-(i.e. if the third data source B<DST> is COMPUTE, the third input value
-will be mapped to the fourth data source in the B<RRD>). This is not very
-error resistant, as you might be sending the wrong data into a RRD.
+By default, the B<update> function expects its data input in the order
+the data sources are defined in the RRD, excluding any COMPUTE data
+sources (i.e. if the third data source B<DST> is COMPUTE, the third
+input value will be mapped to the fourth data source in the B<RRD> and
+so on). This is not very error resistant, as you might be sending the
+wrong data into an RRD.
 
 The template switch allows you to specify which data sources you are
 going to update and in which order. If the data sources specified in
@@ -50,34 +49,36 @@ will abort with an error message.
 
 While it appears possible with the template switch to update data sources
 asynchronously, B<RRDtool> implicitly assigns non-COMPUTE data sources missing
-from the template the I<*UNKNOWN*> value. 
+from the template the I<*UNKNOWN*> value.
 
-Do not specify a value for a COMPUTE B<DST> in the B<update> function. If
-this is done accidentally (and this can only be done using the template switch),
-B<RRDtool> will ignore the value specified for the COMPUTE B<DST>.
+Do not specify a value for a COMPUTE B<DST> in the B<update>
+function. If this is done accidentally (and this can only be done
+using the template switch), B<RRDtool> will ignore the value specified
+for the COMPUTE B<DST>.
 
 =item B<N>|I<timestamp>B<:>I<value>[B<:>I<value>...]
 
-The data used for updating the RRD was acquired at a certain time. This
-time can either be defined in seconds since 1970-01-01. Or by using the
-letter 'N' the update time is set to be the current time. Negative time
-values are subtracted from the current time.
-An AT_STYLE TIME SPECIFICATION (see the I<rrdfetch> documentation) may
-also be used by delimiting the end of the time specification with the '@' character
-instead of a ':'.
-Getting the timing right to the second is especially
-important when you are working with data-sources of type B<COUNTER>,
-B<DERIVE> or B<ABSOLUTE>. 
-
-The remaining elements of the argument are DS updates. The order of this list is
-the same as the order the data sources were defined in the RRA.
-If there is no data for a certain data-source, the letter 
-B<U> (e.g., N:0.1:U:1) can be defined.
-
-The format of the value acquired from the data source is dependent of the
-data source type chosen. Normally it will be numeric, but the data acquisition
-modules may impose their very own parsing of this parameter as long as the colon
-(B<:>) remains the data source value separator.
+The data used for updating the RRD was acquired at a certain
+time. This time can either be defined in seconds since 1970-01-01 or
+by using the letter 'N', in which case the update time is set to be
+the current time. Negative time values are subtracted from the current
+time. An AT_STYLE TIME SPECIFICATION (see the I<rrdfetch>
+documentation) may also be used by delimiting the end of the time
+specification with the '@' character instead of a ':'. Getting the
+timing right to the second is especially important when you are
+working with data-sources of type B<COUNTER>, B<DERIVE> or
+B<ABSOLUTE>.
+
+The remaining elements of the argument are DS updates. The order of
+this list is the same as the order the data sources were defined in
+the RRA. If there is no data for a certain data-source, the letter
+B<U> (e.g., N:0.1:U:1) can be specified.
+
+The format of the value acquired from the data source is dependent on
+the data source type chosen. Normally it will be numeric, but the data
+acquisition modules may impose their very own parsing of this
+parameter as long as the colon (B<:>) remains the data source value
+separator.
 
 =back
 
@@ -92,9 +93,9 @@ C<rrdtool update demo2.rrd 887457267:U 887457521:22 887457903:2.7>
 
 Update the database file demo2.rrd which expects data from a single
 data-source, three times. First with an I<*UNKNOWN*> value then with two
-normal readings. The update interval seems to be around 300 seconds.
+regular readings. The update interval seems to be around 300 seconds.
 
 =head1 AUTHOR
 
-Tobias Oetiker <oetiker@ee.ethz.ch>
+Tobias Oetiker <tobi@oetiker.ch>
 
index fcaaa0dddda2440f6869f8feae8ef24b72d15006..a668a20f33434ecaddf514a75e37a80c7e32c07a 100644 (file)
@@ -1,13 +1,11 @@
 =head1 NAME
 
-rrdtool xport - Export data in XML format based on data from one or several RRD
-
-=for html <div align="right"><a href="rrdxport.pdf">PDF</a> version.</div> 
+rrdxport - Export data in XML format based on data from one or several RRD
 
 =head1 SYNOPSIS
 
-B<rrdtool> B<xport> 
-S<[B<-s>|B<--start> I<seconds>]> 
+B<rrdtool> B<xport>
+S<[B<-s>|B<--start> I<seconds>]>
 S<[B<-e>|B<--end> I<seconds>]>
 S<[B<-m>|B<--maxrows> I<rows>]>
 S<[B<--step> I<value>]>
@@ -17,9 +15,9 @@ S<[B<XPORT>B<:>I<vname>[B<:>I<legend>]]>
 
 =head1 DESCRIPTION
 
-The B<xport> functions main purpose is to write XML formatted
+The B<xport> function's main purpose is to write an XML formatted
 representation of the data stored in one or several B<RRD>s. It
-can also extract numerical reports. 
+can also extract numerical reports.
 
 If no I<XPORT> statements are found, there will be no output.
 
@@ -48,7 +46,13 @@ for details.
 
 =item B<--step> I<value> (default automatic)
 
-See I<rrdgraph> documentation.
+See L<rrdgraph> documentation.
+
+=item B<--enumds> 
+
+The generated xml should contain the data values in enumerated tags.
+
+ <v0>val</v0><v1>val</v1>
 
 =item B<DEF:>I<vname>B<=>I<rrd>B<:>I<ds-name>B<:>I<CF>
 
@@ -63,13 +67,13 @@ See I<rrdgraph> documentation.
 At least one I<XPORT> statement should be present. The values
 referenced by I<vname> are printed. Optionally add a legend.
 
-=over
+=back
 
 =head1 Output format
 
-The output is enclosed in a B<xport> element and contains two
+The output is enclosed in an B<xport> element and contains two
 blocks. The first block is enclosed by a B<meta> element and
-contains some meta data. The second block is enclosed by a 
+contains some meta data. The second block is enclosed by a
 B<data> element and contains the data rows.
 
 Let's assume that the I<xport> command looks like this:
@@ -82,9 +86,9 @@ Let's assume that the I<xport> command looks like this:
           XPORT:xx:"out bytes" \
           XPORT:aa:"in and out bits"
 
-The resulting meta data section (the values will depend on the
+The resulting meta data section is (the values will depend on the
 RRD characteristics):
+
   <meta>
     <start>1020611700</start>
     <step>300</step>
@@ -96,8 +100,8 @@ RRD characteristics):
       <entry>in and out bits</entry>
     </legend>
   </meta>
-  
-The resulting data section:
+
+The resulting data section is:
 
   <data>
     <row><t>1020611700</t><v>3.4000000000e+00</v><v>5.4400000000e+01</v></row>
@@ -136,5 +140,5 @@ The resulting data section:
 
 =head1 AUTHOR
 
-Tobias Oetiker E<lt>oetiker@ee.ethz.chE<gt>
+Tobias Oetiker E<lt>tobi@oetiker.chE<gt>
 
diff --git a/doc/see_also.inc b/doc/see_also.inc
deleted file mode 100644 (file)
index eb2fa5b..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-=head1 SEE ALSO
-
-L<rrdgraph> gives an overview of how B<rrdtool graph> works.
-L<rrdgraph_data> describes B<DEF>,B<CDEF> and B<VDEF> in detail,
-L<rrdgraph_rpn> describes the B<RPN> language used in the B<?DEF> statements,
-L<rrdgraph_graph> page describes all of the graph and print functions.
-
-Make sure to read L<rrdgraph_examples> for tipsE<amp>tricks.
-
-=head1 AUTHOR
-
-Program by Tobias Oetiker E<lt>oetiker@ee.ethz.chE<gt>
-
-This manual page by Alex van den Bogaerdt E<lt>alex@ergens.op.het.netE<gt>
index beeb6f4a2e6f218e10c24395aeb603269ff73a33..a11b944185db50684b70ed918863d793f0346072 100755 (executable)
@@ -8,6 +8,7 @@ use RRDs;
 my $start=time;
 my $rrd="randome.rrd";
 my $name = $0;
+$name =~ s/.*\///g;
 $name =~ s/\.pl.*//g;
 
 RRDs::create ($rrd, "--start",$start-1, "--step",300,
@@ -116,7 +117,7 @@ RRDs::graph "$name-sample.png",
 ;
 
 if ($ERROR = RRDs::error) {
-  print "ERROR: $ERROR\n";
+  die "ERROR: $ERROR\n";
 };
 
 print "This script has created $name.png in the current directory\n";
index 258173b12f475483d30830607e3f1b648201ecd0..9e7dc840ec7e443ded94e337d8200d44fa9081f9 100644 (file)
@@ -4,10 +4,13 @@
 
 #ACLOCAL_M4 = $(top_srcdir)/config/aclocal.m4
 
-EXTRA_DIST = cgi-demo.cgi.in piped-demo.pl.in shared-demo.pl.in \
-       stripes.pl.in bigtops.pl.in minmax.pl.in 4charts.pl.in
+EXTRA_DIST = cgi-demo.cgi.in
 
-examplesdir = $(prefix)/examples
+examplesdir = $(pkgdatadir)/examples
 examples_SCRIPTS = cgi-demo.cgi piped-demo.pl shared-demo.pl \
-       stripes.pl bigtops.pl minmax.pl 4charts.pl
+       stripes.pl bigtops.pl minmax.pl 4charts.pl perftest.pl
+
+cgi-demo.cgi: cgi-demo.cgi.in $(top_builddir)/config.status
+       sed 's,@''exec_prefix@,$(exec_prefix),' cgi-demo.cgi.in > $@
+       chmod a+x $@
 
index b3fa6e41f8aeb18848db0bbf0c5092ecf201c748..997386c5148278d4938fab79758d11fedf7550b8 100755 (executable)
@@ -6,6 +6,7 @@ use RRDs;
 my $start=time;
 my $rrd="randome.rrd";
 my $name = $0;
+$name =~ s/.*\///g;
 $name =~ s/\.pl.*//g;
 
 RRDs::create ($rrd, "--start",$start-1, "--step",300,
@@ -41,7 +42,7 @@ RRDs::graph "$name.png",
 ;
 
 if ($ERROR = RRDs::error) {
-  print "ERROR: $ERROR\n";
+  die "ERROR: $ERROR\n";
 };
 
 
index 29c016932497c9ef3d89726a71f554f18d86905e..3fd0e65ca5c7611e59b5f063fe88af015e3d86eb 100755 (executable)
@@ -6,6 +6,7 @@ use RRDs;
 my $start=time;
 my $rrd="randome.rrd";
 my $name = $0;
+$name =~ s/.*\///g;
 $name =~ s/\.pl.*//g;
 
 RRDs::create ($rrd, "--start",$start-1, "--step",300,
@@ -43,9 +44,9 @@ RRDs::graph "$name.png",
 ;
 
 if ($ERROR = RRDs::error) {
-  print "ERROR: $ERROR\n";
+  die "ERROR: $ERROR\n";
 };
 
 
 print "This script has created $name.png in the current directory\n";
-print "This demonstrates the use of the TIME and % RPN operators\n";
+print "This demonstrates the use of MIN and MAX archives\n";
diff --git a/examples/perftest.pl.in b/examples/perftest.pl.in
new file mode 100755 (executable)
index 0000000..b10f59f
--- /dev/null
@@ -0,0 +1,193 @@
+#! @PERL@
+#
+# $Id:$
+#
+# Created By Tobi Oetiker <tobi@oetiker.ch>
+# Date 2006-10-27
+#
+#makes programm work AFTER install
+
+use lib qw( @prefix@/lib/perl );
+
+print <<NOTE;
+
+RRDtool Performance Tester
+--------------------------
+Runnion on $RRDs::VERSION;
+
+RRDtool update performance is ultimately disk-bound. Since very little data
+does actually get written to disk in a single update, the performance
+is highly dependent on the cache situation in your machine.
+
+This test tries to cater for this. It works like this:
+
+1) Create 100 RRD files (and sync them to disk)
+
+2) Update the 100 RRD file three times in a row.
+   We run the Update several times to see the difference
+   it makes in the cache.
+
+3) Go back to 1)
+
+NOTE
+
+use strict;
+use Time::HiRes qw(time);
+use RRDs;
+use IO::File;
+use Time::HiRes qw( usleep );
+
+sub create($$){
+  my $file = shift;
+  my $time = shift;
+  my $start = time; #since we loaded HiRes
+  RRDs::create  ( $file.".rrd", "-b$time", qw(
+                       -s300                        
+                       DS:in:GAUGE:400:U:U
+                       DS:out:GAUGE:400:U:U
+                       RRA:AVERAGE:0.5:1:600
+                       RRA:AVERAGE:0.5:6:600
+                       RRA:MAX:0.5:6:600
+                       RRA:AVERAGE:0.5:24:600
+                       RRA:MAX:0.5:24:600
+                       RRA:AVERAGE:0.5:144:600
+                       RRA:MAX:0.5:144:600
+               ));
+   my $total = time - $start;
+   my $error =  RRDs::error;
+   die $error if $error;
+   return $total;
+}
+
+sub update($$){
+  my $file = shift;
+  my $time = shift;
+  my $in = rand(1000);
+  my $out = rand(1000);
+  my $start = time;
+  my $ret = RRDs::updatev($file.".rrd", $time.":$in:$out");
+#  print join("",map {"  $_ " . $ret->{$_}."\n" } grep /AVERAGE.\[1\]/, sort keys %$ret)."\n** $time\n\n";
+  # sync updates to disk immediately  
+#  usleep(1) if (rand(3) <1 );
+  my $total = time - $start;
+  my $error =  RRDs::error;
+  die $error if $error;
+  return $total;
+}
+
+sub tune($){
+  my $file = shift;
+  my $start = time;
+  RRDs::tune ($file.".rrd", "-a","in:U","-a","out:U","-d","in:GAUGE","-d","out:GAUGE");
+  my $total = time - $start;
+  my $error =  RRDs::error;
+  die $error if $error;
+  return $total;
+}
+
+sub infofetch($){
+  my $file = shift;
+  my $start = time;
+  my $info = RRDs::info ($file.".rrd");
+  my $error =  RRDs::error;
+  die $error if $error;
+  my $lasttime =  $info->{last_update} - $info->{last_update} % $info->{step};           
+  my $fetch = RRDs::fetch ($file.".rrd",'AVERAGE','-s',$lasttime-1,'-e',$lasttime);
+  my $total = time - $start;
+  my $error =  RRDs::error;
+  die $error if $error;
+  return $total;
+}
+
+sub stddev ($$$){ #http://en.wikipedia.org/wiki/Standard_deviation
+  my $sum = shift;
+  my $squaresum = shift;
+  my $count = shift;
+  return sqrt( 1 / $count * ( $squaresum - $sum*$sum / $count ))
+}
+
+sub makerrds($$$$){
+    my $count = shift;
+    my $total = shift;
+    my $list = shift;
+    my $time = shift;
+    my @files;
+    for (1..$count){
+        my $id = sprintf ("%07d",$total);
+        $id =~ s/^(.)(.)(.)(.)(.)//;
+        push @$list, "$1/$2/$3/$4/$5/$id";    
+        -d "$1" or mkdir "$1";
+        -d "$1/$2" or mkdir "$1/$2";
+        -d "$1/$2/$3" or mkdir "$1/$2/$3";
+        -d "$1/$2/$3/$4" or mkdir "$1/$2/$3/$4";
+        -d "$1/$2/$3/$4/$5" or mkdir "$1/$2/$3/$4/$5";
+       push @files, $list->[$total];
+        create $list->[$total++],$time-2;
+       print STDERR ".";
+    }
+   for (@files){ 
+       my $fd = new IO::File("$_.rrd","r");
+       if (defined $fd) {
+           $fd->sync;
+           $fd->close;
+        } else {
+            warn "failed to sync $_\n";
+        }        
+    }
+    return $count;
+}
+    
+    
+sub main (){
+    mkdir "db-$$" or die $!;
+    chdir "db-$$";
+
+    my $step = 100000; # number of rrds to creat for every round
+    
+    my @path;
+    my $time=int(time);
+
+    my $tracksize = 0;
+    my $uppntr = 0;
+
+    
+    my %squaresum = ( cr => 0, up => 0 );
+    my %sum = ( cr => 0, up => 0 );
+    my %count =( cr => 0, up => 0 );
+
+    my $printtime = time;
+    while (1) {
+        # enhance the track
+           $time += 300;
+        $tracksize += makerrds $step,$tracksize,\@path,$time;            
+        # run benchmark
+        for (0..10){
+           $time += 300;
+            my $count = 0;
+            my $sum = 0;
+            my $squaresum = 0;
+            for (my $i = 0; $i<$tracksize;$i ++){
+               my $elapsed = update($path[$i],$time); 
+               $sum += $elapsed;
+               $squaresum += $elapsed**2;
+               $count++;
+            };
+#            for (my $i = 0; $i<$tracksize;$i ++){
+#             my $fh = new IO::File "$path[$i].rrd","r";
+#             if (defined $fh) {
+#                 $fh->sync;
+#                 $fh->close;
+#                } else {
+#                 warn "failed to sync $path[$i]\n";
+#              }       
+#            }
+            my $ups = $count/$sum;
+            my $sdv = stddev($sum,$squaresum,$count);
+            printf STDERR "%4d %6.0f Up/s (%6.5f sdv)\n",$count,$ups,$sdv;
+        }
+       print STDERR "\n";
+       exit ;
+    }
+}
+
+main;
index 71d69e7135cb93f33da20b8ec97e67eeb24f6482..cafb0f5613ca1e67b1f2a293d33cc47a3ed9a1cf 100755 (executable)
@@ -16,10 +16,12 @@ $SVG = "piped-demo.svg";
 $PNG = "piped-demo.png";
 
 # some magic to find the correct rrdtol executable
+$prefix="@prefix@";
+
 if ( -x "@exec_prefix@/bin/rrdtool") {
    RRDp::start "@exec_prefix@/bin/rrdtool";
-} elsif ( -x "../bin/rrdtool") {
-   RRDp::start "../bin/rrdtool";
+} elsif ( -x "../../../bin/rrdtool") {
+   RRDp::start "../../../bin/rrdtool";
 } else {
    RRDp::start "../src/rrdtool";
 }
index 6d9374f647f026e09a2e43a26afaf9968f62c468..f01c1ae1c886adf294515ef546141471cb8eb08d 100755 (executable)
@@ -142,7 +142,7 @@ for (my $i=0;$i<$GRUNS;$i++) {
           "VRULE:".($now-7200)."#008877:120 Minutes ago";
 
     if ($ERROR = RRDs::error) {
-      print "ERROR: $ERROR\n";
+      die "ERROR: $ERROR\n";
     } else {
       print "Image Size: ${xs}x${ys}\n";
       print "Graph Return:\n",(join "\n", @$graphret),"\n\n";
@@ -154,7 +154,7 @@ for (my $i=0;$i<$GRUNS;$i++) {
 
 my ($start,$step,$names,$array) = RRDs::fetch $RRD1, "AVERAGE";
 $ERROR = RRDs::error;
-print "ERROR: $ERROR\n" if $ERROR ;
+die "ERROR: $ERROR\n" if $ERROR ;
 print "start=$start, step=$step\n";
 print "                    "; 
 map {printf("%12s",$_)} @$names ;
index 5187a56cdf0130930162a6edc1ae5436c2579f4e..362f4992e02743559107dda00b912721c6e982bc 100755 (executable)
@@ -38,7 +38,7 @@ RRDs::graph "stripes.png",
   "COMMENT:alpha=TIME,1200,%,600,LT,a,UNKN,IF",
   "COMMENT:beta=TIME,1200,%,600,GE,b,UNKN,IF\\j";
 if ($ERROR = RRDs::error) {
-  print "ERROR: $ERROR\n";
+  die "ERROR: $ERROR\n";
 };
 
 
diff --git a/favicon.ico b/favicon.ico
new file mode 100644 (file)
index 0000000..7d08dd4
Binary files /dev/null and b/favicon.ico differ
index b53d3d47cf3cbd2990311d4f176a8707566aa08d..efcf5dd45a7308f5aecb1a02e25aa087b0afccb7 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/local/bin/perl -w
+#!/usr/bin/perl -w
 
 require 5.005;
 use strict;
@@ -63,11 +63,15 @@ sub process_font
   $fi{FontSpecificUnicodeNameToChar} = {};
   $fi{filename} = $fn;
   $fi{filename} =~ s/.*\///;
+  $fi{Ascender} = 0;
+  $fi{Descender} = 0;
   open(FH, $fn) || die "Can't open $fn\n";
   print STDERR "Reads global font info\n" if $q;
   while (<FH>) {
     chomp;
     next if /^\s*$/ || /^\s*#/;
+    $fi{Ascender} = $1 if /^Ascender\s+(-?\d+)/;
+    $fi{Descender} = $1 if /^Descender\s+(-?\d+)/;
     last if /^StartCharMetrics/;
     next unless (/^(\S+)\s+(\S(.*\S)?)/);
     my $id = $1;
@@ -244,8 +248,8 @@ sub write_font
      $kerning_data_count + 2 * $highchars_count +
      3 * 2 * $ligatures_count;
   $info_code .= $indent1 . "{ /* $$fiR{filename}   $packedSize bytes */\n";
-    $info_code .= $i2 . "\"$$fiR{AfmFontName}\",";
-    $info_code .= " \"$$fiR{AfmFullName}\",\n";
+    $info_code .= $i2 . "\"$$fiR{AfmFontName}\", \"$$fiR{AfmFullName}\",\n";
+    $info_code .= $i2 . $$fiR{Ascender} . ", " . $$fiR{Descender} . ",\n";
     $info_code .= $i2 . $$fiR{widthsACName} . ",\n";
     $info_code .= $i2 . $$fiR{kerning_indexACName} . ",\n";
     $info_code .= $i2 . $$fiR{kerning_dataACName} . ",\n";
@@ -448,7 +452,7 @@ sub main
   print CFILE ${$font_code{$_}}{TABLES} foreach @fonts;
   print CFILE "const afm_fontinfo afm_fontinfolist[] = {\n";
   print CFILE ${$font_code{$_}}{INFO} foreach @fonts;
-  print CFILE $indent1 . "{ 0, 0, 0 }\n";
+  print CFILE $indent1 . "{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }\n";
   print CFILE $indent0 . "};\n";
   print CFILE $indent0 . "const int afm_fontinfo_count = ",
     ($#fonts + 1), ";\n";
diff --git a/netware/Makefile b/netware/Makefile
new file mode 100644 (file)
index 0000000..c138dfa
--- /dev/null
@@ -0,0 +1,555 @@
+# Gnu Makefile for NetWare target
+# for use with gcc/nlmconv or Metrowerks CodeWarrior compiler
+# use with: make -f Makefile [help|all|clean|dev|devclean|dist|distclean]
+#
+# $id: $
+#
+
+DESCR  = Round Robin Database Tool $(RRD_VERSION_STR)
+COPYR  = Copyright (c) 1997-2007 by Tobias Oetiker
+WWWURL = http://www.rrdtool.org/
+MTSAFE = YES
+#SCREEN        = $(DESCR)
+STACK  = 65535
+# Comment the line below if you dont want to load protected automatically.
+#LDRING        = 3
+
+# You can set the default font used in graphs.
+# If not set here RRD defaults to DejaVuSansMono-Roman.ttf
+#RRD_DEFAULT_FONT = "sys:/java/nwgfx/lib/x11/fonts/ttf/tt0003m_.ttf"
+#RRD_DEFAULT_FONT = "VeraMono.ttf"
+
+# Vertical label angle: 90.0 (default) or 270.0
+RRDGRAPH_YLEGEND_ANGLE = 90.0
+
+# Set to one if you want to have piecharts.
+WITH_PIECHART = 0
+
+# Set the extension used for rrdcgi.
+ifndef CGIEXT
+CGIEXT = nlm
+endif
+
+# Edit the path below to point to your Novell NDK.
+ifndef NDKBASE
+NDKBASE        = c:/novell
+endif
+
+# Base for the lib sources
+ifndef LIBBASE
+LIBBASE        = ../..
+endif
+# All library code is statically linked to avoid problems with other lib NLMs.
+# Edit the path below to point to your libpng sources or set environment var.
+ifndef LIBPNG
+LIBPNG = $(LIBBASE)/libpng-1.2.16
+endif
+# Edit the path below to point to your freetype sources or set environment var.
+ifndef LIBFT2
+LIBFT2 = $(LIBBASE)/freetype-2.3.4
+endif
+# Edit the path below to point to your libart sources or set environment var.
+ifndef LIBART
+LIBART = $(LIBBASE)/libart_lgpl-2.3.17
+endif
+# Edit the path below to point to your zlib sources or set environment var.
+ifndef ZLIBSDK
+ZLIBSDK        = $(LIBBASE)/zlib-1.2.3
+endif
+
+# Edit the path below to point to your distribution folder.
+ifndef DISTDIR
+DISTDIR        = rrdtool-$(RRD_VERSION_STR)-nw
+endif
+DISTARC = $(DISTDIR).zip
+
+# Edit the path below to point to your distribution folder.
+ifndef DEVLDIR
+DEVLDIR        = rrdtool-$(RRD_VERSION_STR)-sdk-nw
+endif
+DEVLARC = $(DEVLDIR).zip
+
+# whatever...
+# NO_NULL_REALLOC = 1
+
+# Edit the var below to point to your lib architecture.
+ifndef LIBARCH
+# LIBARCH = CLIB
+LIBARCH = LIBC
+endif
+
+# The following line defines your compiler.
+ifdef METROWERKS
+       CC = mwccnlm
+else
+       CC = gcc
+endif
+# RM   = rm -f
+CP     = cp -afv
+# if you want to mark the target as MTSAFE you will need a tool for
+# generating the xdc data for the linker; here's a minimal tool:
+# http://www.gknw.net/development/prgtools/mkxdc.zip
+MPKXDC = mkxdc
+# CodeWarrior is too stupid to set the internal name properly when
+# the extension is not a NLM and not a registered type. So we need
+# to fix that after linking (since CGI isnt a known type - argh!):
+# http://www.gknw.net/development/prgtools/fixnlmname.zip
+FIXNLMN        = fixnlmname #-q
+# Here you can find a native Win32 binary of the original awk:
+# http://www.gknw.net/development/prgtools/awk.zip
+AWK    = awk
+ZIP    = zip -qzr9
+MV     = mv -fv
+
+# must be equal to DEBUG or NDEBUG
+DB     = NDEBUG
+# DB   = DEBUG
+# Optimization: -O<n> or debugging: -g
+ifeq ($(DB),NDEBUG)
+       OPT     = -O2
+       OBJDIR  = release
+else
+       OPT     = -g
+       OBJDIR  = debug
+endif
+
+# Project root
+PROOT  = ..
+
+# Include the version info retrieved from source.
+-include $(OBJDIR)/version.inc
+
+# Global flags for all compilers
+CFLAGS = $(OPT) -D$(DB) -nostdinc -DNETWARE -DN_PLAT_NLM -D_POSIX_SOURCE
+CFLAGS += -DHAVE_CONFIG_H
+
+ifeq ($(CC),mwccnlm)
+LD     = mwldnlm
+LDFLAGS        = -nostdlib $^ $(PRELUDE) $(LDLIBS) -o $@ -commandfile
+AR     = $(LD)
+ARFLAGS        = -nostdlib -type library -o
+LIBEXT = lib
+#RANLIB        =
+CFLAGS += -gccinc -inline off -opt nointrinsics -proc 586
+CFLAGS += -relax_pointers
+#CFLAGS        += -w on,nounused,nounusedexpr # -ansi strict
+ifeq ($(LIBARCH),LIBC)
+       PRELUDE = $(SDK_LIBC)/imports/libcpre.o
+       CFLAGS += -align 4
+else
+       PRELUDE = "$(METROWERKS)/Novell Support/libraries/runtime/prelude.obj"
+       CFLAGS += -include "$(METROWERKS)/Novell Support/headers/nlm_prefix.h"
+       CFLAGS += -align 1
+endif
+else
+LD     = nlmconv
+LDFLAGS        = -T
+AR     = ar
+ARFLAGS        = -cq
+LIBEXT = a
+RANLIB = ranlib
+CFLAGS += -fno-builtin -fpcc-struct-return -fno-strict-aliasing
+CFLAGS += -Wall -Wno-unused # -pedantic
+ifeq ($(LIBARCH),LIBC)
+       PRELUDE = $(SDK_LIBC)/imports/libcpre.gcc.o
+else
+       PRELUDE = $(NDK_ROOT)/pre/prelude.o
+       CFLAGS += -include $(NDKBASE)/nlmconv/genlm.h
+endif
+endif
+
+ifeq ($(findstring linux,$(OSTYPE)),linux)
+#include $(NDKBASE)/nlmconv/ncpfs.inc
+DL     = '
+DS     = /
+else
+DS     = \\
+endif
+
+ifeq ($(MTSAFE),YES)
+       XDCOPT = -n
+endif
+ifeq ($(MTSAFE),NO)
+       XDCOPT = -u
+endif
+ifndef DESCR
+       DESCR = $(notdir $(@:.def=)) Command Extension
+endif
+DESCR += ($(LIBARCH)) - $(CC) build
+
+NDK_ROOT = $(NDKBASE)/ndk
+SDK_CLIB = $(NDK_ROOT)/nwsdk
+SDK_LIBC = $(NDK_ROOT)/libc
+
+INCLUDES += -I$(PROOT) -I$(PROOT)/src -I$(LIBPNG) -I$(LIBFT2)/include -I$(LIBART) -I$(ZLIBSDK)
+
+ifeq ($(LIBARCH),LIBC)
+       INCLUDES += -I$(SDK_LIBC)/include -I$(SDK_LIBC)/include/nks
+else
+       INCLUDES += -I$(SDK_CLIB)/include/nlm -I$(SDK_CLIB)/include
+endif
+
+CFLAGS += $(INCLUDES)
+
+vpath %.c $(PROOT)/src $(LIBPNG) $(LIBART)/libart_lgpl $(ZLIBSDK)
+
+RRDLIBOBJS     = \
+       $(OBJDIR)/rrd_afm.o \
+       $(OBJDIR)/rrd_afm_data.o \
+       $(OBJDIR)/rrd_create.o \
+       $(OBJDIR)/rrd_diff.o \
+       $(OBJDIR)/rrd_dump.o \
+       $(OBJDIR)/rrd_error.o \
+       $(OBJDIR)/rrd_fetch.o \
+       $(OBJDIR)/rrd_first.o \
+       $(OBJDIR)/rrd_format.o \
+       $(OBJDIR)/rrd_gfx.o \
+       $(OBJDIR)/rrd_graph.o \
+       $(OBJDIR)/rrd_graph_helper.o \
+       $(OBJDIR)/rrd_hw.o \
+       $(OBJDIR)/rrd_info.o \
+       $(OBJDIR)/rrd_last.o \
+       $(OBJDIR)/rrd_lastupdate.o \
+       $(OBJDIR)/rrd_nan_inf.o \
+       $(OBJDIR)/rrd_open.o \
+       $(OBJDIR)/rrd_resize.o \
+       $(OBJDIR)/rrd_restore.o \
+       $(OBJDIR)/rrd_rpncalc.o \
+       $(OBJDIR)/rrd_tune.o \
+       $(OBJDIR)/rrd_update.o \
+       $(OBJDIR)/rrd_version.o \
+       $(OBJDIR)/rrd_xport.o \
+       $(OBJDIR)/rrd_thread_safe.o \
+       $(EOLIST)
+
+XLIBOBJS       = \
+       $(OBJDIR)/rrd_getopt.o \
+       $(OBJDIR)/rrd_getopt1.o \
+       $(OBJDIR)/art_rgba_svp.o \
+       $(OBJDIR)/hash_32.o \
+       $(OBJDIR)/parsetime.o \
+       $(OBJDIR)/pngsize.o \
+       $(EOLIST)
+
+PNGLIBOBJS     = \
+       $(OBJDIR)/png.o \
+       $(OBJDIR)/pngerror.o \
+       $(OBJDIR)/pngget.o \
+       $(OBJDIR)/pngmem.o \
+       $(OBJDIR)/pngpread.o \
+       $(OBJDIR)/pngread.o \
+       $(OBJDIR)/pngrio.o \
+       $(OBJDIR)/pngrtran.o \
+       $(OBJDIR)/pngrutil.o \
+       $(OBJDIR)/pngset.o \
+       $(OBJDIR)/pngtrans.o \
+       $(OBJDIR)/pngwio.o \
+       $(OBJDIR)/pngwrite.o \
+       $(OBJDIR)/pngwtran.o \
+       $(OBJDIR)/pngwutil.o \
+       $(EOLIST)
+ifeq "$(wildcard $(LIBPNG)/pnggccrd.c)" "$(LIBPNG)/pnggccrd.c"
+PNGLIBOBJS     += \
+       $(OBJDIR)/pnggccrd.o \
+       $(OBJDIR)/pngvcrd.o \
+       $(EOLIST)
+endif
+
+ZLIBOBJS       = \
+       $(OBJDIR)/adler32.o \
+       $(OBJDIR)/compress.o \
+       $(OBJDIR)/crc32.o \
+       $(OBJDIR)/deflate.o \
+       $(OBJDIR)/inflate.o \
+       $(OBJDIR)/inffast.o \
+       $(OBJDIR)/inftrees.o \
+       $(OBJDIR)/trees.o \
+       $(OBJDIR)/zutil.o \
+       $(EOLIST)
+ifeq "$(wildcard $(ZLIBSDK)/infblock.c)" "$(ZLIBSDK)/infblock.c"
+ZLIBOBJS       += \
+       $(OBJDIR)/infblock.o \
+       $(OBJDIR)/infcodes.o \
+       $(OBJDIR)/infutil.o \
+       $(EOLIST)
+endif
+
+ARTLIBOBJS     = \
+       $(patsubst $(LIBART)/libart_lgpl/%.c,$(OBJDIR)/%.o,$(wildcard $(LIBART)/libart_lgpl/art_*.c))
+
+OBJS   := $(RRDLIBOBJS) $(XLIBOBJS) $(PNGLIBOBJS) $(ARTLIBOBJS) $(ZLIBOBJS)
+OBJCGI := $(OBJS) $(OBJDIR)/rrd_cgi.o
+OBJTOOL        := $(OBJS) $(OBJDIR)/rrd_tool.o
+
+LDLIBS += $(LIBFT2)/builds/netware/libc/libft2.$(LIBEXT)
+
+
+all: rrdtool rrdcgi
+
+rrdtool: $(OBJDIR) $(PROOT)/rrd_config.h $(OBJDIR)/rrdtool.nlm
+rrdcgi: $(OBJDIR) $(PROOT)/rrd_config.h $(OBJDIR)/rrdcgi.$(CGIEXT)
+librrd: $(OBJDIR) $(PROOT)/rrd_config.h $(OBJDIR)/librrd.$(LIBEXT)
+
+FORCE: ;
+
+dist: all $(DISTDIR) $(DISTDIR)/readme.txt
+       @-$(CP) $(OBJDIR)/rrdcgi.$(CGIEXT) $(DISTDIR)
+       @-$(CP) $(OBJDIR)/rrdtool.nlm $(DISTDIR)
+       @-$(CP) $(PROOT)/src/*.ttf $(DISTDIR)
+       @-$(CP) $(PROOT)/CHANGES $(DISTDIR)
+       @-$(CP) $(PROOT)/COPYING $(DISTDIR)
+       @-$(CP) $(PROOT)/COPYRIGHT $(DISTDIR)
+       @-$(CP) $(PROOT)/NEWS $(DISTDIR)
+       @-$(CP) $(PROOT)/README $(DISTDIR)
+       @echo Creating $(DISTARC)
+       @$(ZIP) $(DISTARC) $(DISTDIR)/* < $(DISTDIR)/readme.txt
+
+dev: librrd $(DEVLDIR) $(DEVLDIR)/readme.txt
+       @-mkdir $(DEVLDIR)$(DS)include
+       @-mkdir $(DEVLDIR)$(DS)lib
+       @-mkdir $(DEVLDIR)$(DS)src
+       @-$(CP) $(OBJDIR)/librrd.$(LIBEXT) $(DEVLDIR)/lib
+       @-$(CP) $(PROOT)/rrd_config.h $(DEVLDIR)/include
+       @-$(CP) $(PROOT)/src/rrd.h $(DEVLDIR)/include
+       @-$(CP) $(PROOT)/src/*.ttf $(DEVLDIR)/src
+       @-$(CP) $(PROOT)/CHANGES $(DEVLDIR)
+       @-$(CP) $(PROOT)/COPYING $(DEVLDIR)
+       @-$(CP) $(PROOT)/COPYRIGHT $(DEVLDIR)
+       @-$(CP) $(PROOT)/NEWS $(DEVLDIR)
+       @-$(CP) $(PROOT)/README $(DEVLDIR)
+       @echo Creating $(DEVLARC)
+       @$(ZIP) $(DEVLARC) $(DEVLDIR)/* < $(DEVLDIR)/readme.txt
+
+clean:
+       -$(RM) -r $(OBJDIR)
+       -$(RM) $(PROOT)/rrd_config.h
+
+distclean: clean
+       -$(RM) -r $(DISTDIR)
+       -$(RM) $(DISTARC)
+
+devclean: clean
+       -$(RM) -r $(DEVLDIR)
+       -$(RM) $(DEVLARC)
+
+$(OBJDIR):
+       @mkdir $@
+
+$(DISTDIR):
+       @mkdir $@
+
+$(DEVLDIR):
+       @mkdir $@
+
+$(OBJDIR)/version.inc: $(PROOT)/configure.ac $(OBJDIR) $(PROOT)/src/get_ver.awk
+       @echo Creating $@
+       @$(AWK) -f $(PROOT)/src/get_ver.awk $< > $@
+
+$(OBJDIR)/%.o: %.c
+       @echo Compiling $<
+       @$(CC) $(CFLAGS) -c $< -o $@
+
+$(OBJDIR)/rrdcgi.$(CGIEXT): $(OBJCGI) $(OBJDIR)/rrdcgi.def $(OBJDIR)/rrdcgi.xdc
+       @echo Linking $@
+       @-$(RM) $@
+       @$(LD) $(LDFLAGS) $(@:.$(CGIEXT)=.def)
+ifeq ($(LD),nlmconv)
+       @$(MV) $(notdir $@) $@
+endif
+ifneq ($(CGIEXT),nlm)
+ifeq ($(LD),mwldnlm)
+       @$(FIXNLMN) $@
+endif
+endif
+
+$(OBJDIR)/rrdtool.nlm: $(OBJTOOL) $(OBJDIR)/rrdtool.def $(OBJDIR)/rrdtool.xdc
+       @echo Linking $@
+       @-$(RM) $@
+       @$(LD) $(LDFLAGS) $(@:.nlm=.def)
+ifeq ($(LD),nlmconv)
+       @$(MV) $(notdir $@) $@
+endif
+
+$(OBJDIR)/librrd.$(LIBEXT): $(OBJS)
+       @echo Creating $@
+       @-$(RM) $@
+       @$(AR) $(ARFLAGS) $@ $^
+ifdef RANLIB
+       @$(RANLIB) $@
+endif
+
+$(OBJDIR)/%.xdc: Makefile
+       @echo Creating $@
+       @$(MPKXDC) $(XDCOPT) $@
+
+$(OBJDIR)/%.def: Makefile $(OBJDIR)/version.inc
+       @echo $(DL)# DEF Linker File for use with gcc and nlmconv$(DL) > $@
+       @echo $(DL)# or with Codewarrior command line compiler.$(DL) >> $@
+       @echo $(DL)# Do not edit this file - it is created by make!$(DL) >> $@
+       @echo $(DL)# All your changes will be lost!!$(DL) >> $@
+       @echo $(DL)#$(DL) >> $@
+       @echo $(DL)copyright "$(COPYR)"$(DL) >> $@
+       @echo $(DL)description "$(DESCR)"$(DL) >> $@
+       @echo $(DL)version $(RRD_VERSION)$(DL) >> $@
+ifdef NLMTYPE
+       @echo $(DL)type $(NLMTYPE)$(DL) >> $@
+else
+       @echo $(DL)type 0$(DL) >> $@
+endif
+ifdef STACK
+       @echo $(DL)stack $(STACK)$(DL) >> $@
+endif
+       @echo $(DL)threadname "$(notdir $(@:.def=))"$(DL) >> $@
+ifdef SCREEN
+       @echo $(DL)screenname "$(SCREEN)"$(DL) >> $@
+else
+       @echo $(DL)screenname "DEFAULT"$(DL) >> $@
+endif
+ifeq ($(DB),DEBUG)
+       @echo $(DL)debug$(DL) >> $@
+endif
+ifeq ($(LIBARCH),CLIB)
+       @echo $(DL)start _Prelude$(DL) >> $@
+       @echo $(DL)exit _Stop$(DL) >> $@
+       @echo $(DL)import @$(NDK_ROOT)/nwsdk/imports/clib.imp$(DL) >> $@
+       @echo $(DL)import @$(NDK_ROOT)/nwsdk/imports/threads.imp$(DL) >> $@
+       @echo $(DL)import @$(NDK_ROOT)/nwsdk/imports/nlmlib.imp$(DL) >> $@
+       @echo $(DL)module clib$(DL) >> $@
+else
+       @echo $(DL)start _LibCPrelude$(DL) >> $@
+       @echo $(DL)exit _LibCPostlude$(DL) >> $@
+       @echo $(DL)check _LibCCheckUnload$(DL) >> $@
+       @echo $(DL)import @$(NDK_ROOT)/libc/imports/libc.imp$(DL) >> $@
+       @echo $(DL)import @$(NDK_ROOT)/libc/imports/netware.imp$(DL) >> $@
+       @echo $(DL)module libc$(DL) >> $@
+       @echo $(DL)pseudopreemption$(DL) >> $@
+       @echo $(DL)flag_on 64$(DL) >> $@
+endif
+ifeq ($(LDRING),0)
+       @echo $(DL)flag_on 16$(DL) >> $@
+endif
+ifeq ($(LDRING),3)
+       @echo $(DL)flag_on 512$(DL) >> $@
+endif
+ifdef XDCOPT
+       @echo $(DL)xdcdata $(@:.def=.xdc)$(DL) >> $@
+endif
+ifeq ($(LD),nlmconv)
+       @echo $(DL)input $(OBJS) $(LDLIBS)$(DL) >> $@
+       @echo $(DL)input $(PRELUDE)$(DL) >> $@
+       @echo $(DL)output $(notdir $(@:.def=.nlm))$(DL) >> $@
+endif
+
+$(PROOT)/rrd_config.h: FORCE Makefile $(OBJDIR)/version.inc
+       @echo Creating $@
+       @echo $(DL)/* $(notdir $@) for NetWare target.$(DL) > $@
+       @echo $(DL)** Do not edit this file - it is created by make!$(DL) >> $@
+       @echo $(DL)** All your changes will be lost!!$(DL) >> $@
+       @echo $(DL)*/$(DL) >> $@
+       @echo $(DL)#ifndef NETWARE$(DL) >> $@
+       @echo $(DL)#error This $(notdir $@) is created for NetWare platform!$(DL) >> $@
+       @echo $(DL)#endif$(DL) >> $@
+       @echo $(DL)#ifndef RRD_CONFIG_H$(DL) >> $@
+       @echo $(DL)#define RRD_CONFIG_H$(DL) >> $@
+       @echo $(DL)#define OS "i586-pc-NetWare"$(DL) >> $@
+       @echo $(DL)#define PACKAGE_VERSION "$(RRD_VERSION_STR)"$(DL) >> $@
+       @echo $(DL)#define PACKAGE_BUGREPORT "tobi@oetiker.ch"$(DL) >> $@
+       @echo $(DL)#define NUMVERS $(RRD_NUMVERS)$(DL) >> $@
+       @echo $(DL)#define HAVE_ASSERT_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_DLFCN_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_DLOPEN 1$(DL) >> $@
+       @echo $(DL)#define HAVE_ERR_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_ERRNO_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_FCNTL_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_FIONBIO 1$(DL) >> $@
+       @echo $(DL)#define HAVE_FLOAT_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_GETTIMEOFDAY 1$(DL) >> $@
+       @echo $(DL)#define HAVE_INTTYPES_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_LIMITS_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_LONGLONG 1$(DL) >> $@
+       @echo $(DL)#define HAVE_LOCALE_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_MALLOC_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_MATH_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_MBSTOWCS 1$(DL) >> $@
+       @echo $(DL)#define HAVE_MEMMOVE 1$(DL) >> $@
+       @echo $(DL)#define HAVE_MKTIME 1$(DL) >> $@
+       @echo $(DL)#define HAVE_SELECT 1$(DL) >> $@
+       @echo $(DL)#define HAVE_SETLOCALE 1$(DL) >> $@
+       @echo $(DL)#define HAVE_SETJMP_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_SNPRINTF 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STDARG_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STDDEF_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STDINT_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STDLIB_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STRCASECMP 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STRDUP 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STRFTIME 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STRING_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STRLCAT 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STRLCPY 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STRSTR 1$(DL) >> $@
+       @echo $(DL)#define HAVE_SYS_PARAM_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_SYS_SELECT_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_SYS_STAT_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_SYS_TIME_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_SYS_TYPES_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_TIME_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_TZSET 1$(DL) >> $@
+       @echo $(DL)#define HAVE_UNAME 1$(DL) >> $@
+       @echo $(DL)#define HAVE_VSNPRINTF 1$(DL) >> $@
+       @echo $(DL)#define STDC_HEADERS 1$(DL) >> $@
+       @echo $(DL)#define TIME_WITH_SYS_TIME 1$(DL) >> $@
+       @echo $(DL)#define HAVE_ZLIB_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_LIBZ 1$(DL) >> $@
+ifdef NO_NULL_REALLOC
+       @echo $(DL)#define NO_NULL_REALLOC 1$(DL) >> $@
+       @echo $(DL)#define rrd_realloc(a,b) ( (a) == NULL ? malloc( (b) ) : realloc( (a) , (b) ))$(DL) >> $@
+else
+       @echo $(DL)#define rrd_realloc(a,b) realloc((a), (b))$(DL) >> $@
+endif
+ifdef RRD_DEFAULT_FONT
+       @echo $(DL)#define RRD_DEFAULT_FONT $(RRD_DEFAULT_FONT)$(DL) >> $@
+endif
+       @echo $(DL)#define RRDGRAPH_YLEGEND_ANGLE $(RRDGRAPH_YLEGEND_ANGLE)$(DL) >> $@
+ifdef WITH_PIECHART
+       @echo $(DL)#define WITH_PIECHART $(WITH_PIECHART)$(DL) >> $@
+endif
+       @echo $(DL)#endif /* RRD_CONFIG_H */$(DL) >> $@
+
+$(DISTDIR)/readme.txt: Makefile
+       @echo Creating $@
+       @echo $(DL)This is a binary distribution for NetWare platform.$(DL) > $@
+       @echo $(DL)RRDTool version $(RRD_VERSION_STR)$(DL) >> $@
+       @echo $(DL)Please download the complete RRDTool package for$(DL) >> $@
+       @echo $(DL)any further documentation:$(DL) >> $@
+       @echo $(DL)$(WWWURL)$(DL) >> $@
+
+$(DEVLDIR)/readme.txt: Makefile
+       @echo Creating $@
+       @echo $(DL)This is a development distribution for NetWare platform.$(DL) > $@
+       @echo $(DL)RRDTool version $(RRD_VERSION_STR)$(DL) >> $@
+       @echo $(DL)Please download the complete RRDTool package for$(DL) >> $@
+       @echo $(DL)any further documentation:$(DL) >> $@
+       @echo $(DL)$(WWWURL)$(DL) >> $@
+
+help:
+       @echo $(DL)===========================================================$(DL)
+       @echo $(DL)Novell NDK Base = $(NDKBASE)$(DL)
+       @echo $(DL)libpng Source   = $(LIBPNG)$(DL)
+       @echo $(DL)libart Source   = $(LIBART)$(DL)
+       @echo $(DL)Freetype 2 SDK  = $(LIBFT2)$(DL)
+       @echo $(DL)Zlib SDK        = $(ZLIBSDK)$(DL)
+       @echo $(DL)===========================================================$(DL)
+       @echo $(DL)RRDTool $(RRD_VERSION_STR) - available targets are:$(DL)
+       @echo $(DL)$(MAKE) all$(DL)
+       @echo $(DL)$(MAKE) rrdtool$(DL)
+       @echo $(DL)$(MAKE) rrdcgi$(DL)
+       @echo $(DL)$(MAKE) librrd$(DL)
+       @echo $(DL)$(MAKE) clean$(DL)
+       @echo $(DL)$(MAKE) dev$(DL)
+       @echo $(DL)$(MAKE) devclean$(DL)
+       @echo $(DL)$(MAKE) dist$(DL)
+       @echo $(DL)$(MAKE) distclean$(DL)
+       @echo $(DL)===========================================================$(DL)
+
+
diff --git a/rrdtool-1.2-release b/rrdtool-1.2-release
new file mode 100755 (executable)
index 0000000..b364a3f
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/sh
+set -e
+VERSION=`perl -n -e 'm/\QAC_INIT([rrdtool],[\E(.+?)\Q])\E/ && print $1' configure.ac`
+PERLVERS=`perl -n -e 'm/NUMVERS=(\d+\.\d+)/ && print $1' configure.ac`
+set -x
+perl -i -p -e 's/^\$VERSION.+/\$VERSION='$PERLVERS';/' bindings/perl-*/*.pm
+perl -i -p -e 's/RRDtool 1\S+/RRDtool '$VERSION'/ && s/Copyright.+?Oetiker.+\d{4}/Copyright by Tobi Oetiker, 1997-2007/' src/*.h src/*.c
+perl -i -p -e 's/^Version:.+/Version: '$VERSION'/' rrdtool.spec
+perl -i -p -e 's/rrdtool-[\.\d]+\d(pre\d+)?(rc\d+)?/rrdtool-'$VERSION'/g' doc/rrdbuild.pod
+svn diff 
+echo "Tagging and releasing rrdtool $VERSION ($PERLVERS). Press any Key to continue."
+read somekey
+svn commit -m "prepare for the release of rrdtool-$VERSION"
+mkdir /tmp/rrdtool-$$
+OPWD=`pwd`
+cd /tmp/rrdtool-$$
+svn checkout svn://svn.oetiker.ch/rrdtool/branches/1.2/program .
+svn log --stop-on-copy --xml --verbose svn://svn.oetiker.ch/rrdtool/branches/1.2/program | \
+    xsltproc --stringparam strip-prefix branches/1.2/program $OPWD/svn2cl.xsl -  >CHANGES
+sh MakeMakefile
+PKG_CONFIG_PATH=/usr/pack/rrdtool-1.2svn-to/i686-debian-linux3.1/lib/pkgconfig/
+export PKG_CONFIG_PATH
+./configure
+make dist
+# do a test build
+tar zxvf rrdtool*.tar.gz
+cd rrdtool-$VERSION
+./configure
+make
+src/rrdtool
+cd ..
+scp CHANGES rrdtool*.tar.gz  oposs@james:public_html/rrdtool/pub/
+ssh oposs@james "cd public_html/rrdtool/pub/;rm rrdtool.tar.gz;ln -s rrdtool-$VERSION.tar.gz rrdtool.tar.gz"
+cd ..
+rm -rf rrdtool-$$
+svn copy -m "tagging version $VERSION" svn://svn.oetiker.ch/rrdtool/branches/1.2/program svn://svn.oetiker.ch/rrdtool/tags/$VERSION
+
index 738ce40c05db4f3af7266a8ed326dab9b9d2aec7..97871d1f3487e2a72073000af68bce371a21270e 100644 (file)
-%define cvsdate cvs-snap
-%define cvsver %(echo %{cvsdate} | tr -d -)
-%define sover 1.0.0
-
-Summary: Round Robin Database Tools
+Summary: Round Robin Database Tool to store and display time-series data
 Name: rrdtool
-Version: 1.1.0
-Release: %{cvsver}
+Version: 1.2.23
+Release: 3%{?dist}
 License: GPL
 Group: Applications/Databases
-Source: http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/pub/beta/rrdtool-cvs-snap.tar.gz
-URL: http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/
-Buildroot: /tmp/%{name}-root
+URL: http://oss.oetiker.ch/%{name}/
+Source: http://oss.oetiker.ch/%{name}/pub/%{name}-%{version}.tar.gz
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+BuildRequires: gcc-c++, openssl-devel
+BuildRequires: libpng-devel, zlib-devel, libart_lgpl-devel >= 2.0
+BuildRequires: freetype-devel, python-devel >= 2.3
+Requires: perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version))
 
-BuildRequires: perl
-BuildRequires: cgilib-devel
-BuildRequires: freetype-devel libart_lgpl-devel libpng-devel zlib-devel
+%{!?python_sitearch: %define python_sitearch %(%{__python} -c 'from distutils import sysconfig; print sysconfig.get_python_lib(1)')}
+%{!?python_version: %define python_version %(%{__python} -c 'import sys; print sys.version.split(" ")[0]')}
 
 %description
-It is pretty easy to gather status information from all sorts of things,
-ranging from the temperature in your office to the number of octets which
-have passed through the FDDI interface of your router. But it is not so
-trivial to store this data in a efficient and systematic manner. This is
-where RRDtool kicks in. It lets you log and analyze the data you gather from
-all kinds of data-sources (DS). The data analysis part of RRDtool is based
-on the ability to quickly generate graphical representations of the data
-values collected over a definable time period.
+RRD is the Acronym for Round Robin Database. RRD is a system to store and
+display time-series data (i.e. network bandwidth, machine-room temperature,
+server load average). It stores the data in a very compact way that will not
+expand over time, and it presents useful graphs by processing the data to
+enforce a certain data density. It can be used either via simple wrapper
+scripts (from shell or Perl) or via frontends that poll network devices and
+put a friendly user interface on it.
 
 %package devel
-Summary: RRD Tool development libraries and header files
+Summary: RRDtool libraries and header files
 Group: Development/Libraries
-Requires: %{name} = %{version}
+Requires: %{name} = %{version}-%{release}
 
 %description devel
-The RRD Tools development library.
+RRD is the Acronym for Round Robin Database. RRD is a system to store and
+display time-series data (i.e. network bandwidth, machine-room temperature,
+server load average). This package allow you to use directly this library.
 
-%package perl
-Summary: RRD Tool Perl interface
-Group: Applications/Databases
-Requires: %{name} = %{version}
+%package doc
+Summary: RRDtool documentation
+Group: Documentation
+
+%description doc
+RRD is the Acronym for Round Robin Database. RRD is a system to store and
+display time-series data (i.e. network bandwidth, machine-room temperature,
+server load average). This package contains documentation on using RRD.
+
+%package -n perl-%{name}
+Summary: Perl RRDtool bindings
+Group: Development/Languages
+Requires: %{name} = %{version}-%{release}
+Obsoletes: %{name}-perl <= %{version}
+Provides: %{name}-perl = %{version}
 
-%description perl
-The RRD Tools Perl modules.
+%description -n perl-%{name}
+The Perl RRDtool bindings
+
+%package -n python-%{name}
+Summary: Python RRDtool bindings
+Group: Development/Languages
+BuildRequires: python
+Requires: python >= %{python_version}
+Requires: %{name} = %{version}-%{release}
+
+%description -n python-%{name}
+Python RRDtool bindings.
 
 %prep
-%setup -q -n rrdtool-%{cvsdate}
+%setup
+
+# Fix to find correct python dir on lib64
+%{__perl} -pi -e 's|get_python_lib\(0,0,prefix|get_python_lib\(1,0,prefix|g' \
+    configure
 
-%define deffont %{_datadir}/%{name}/fonts/VeraMono.ttf
+# Shouldn't be necessary when using --libdir, but
+# introduces hardcoded rpaths where it shouldn't,
+# if not done...
+%{__perl} -pi.orig -e 's|/lib\b|/%{_lib}|g' \
+    configure Makefile.in
 
 %build
-CPPFLAGS="-I/usr/include/libart-2.0 -I/usr/include/freetype2"
-export CPPFLAGS
-%configure
-make
+%configure \
+    --program-prefix="%{?_program_prefix}" \
+    --libdir=%{_libdir} \
+    --disable-static \
+    --with-pic \
+    --with-perl-options='INSTALLDIRS="vendor"'
+
+# Fix another rpath issue
+%{__perl} -pi.orig -e 's|-Wl,--rpath -Wl,\$rp||g' \
+    bindings/perl-shared/Makefile.PL
+
+# Force RRDp bits where we want 'em, not sure yet why the
+# --with-perl-options and --libdir don't take
+pushd bindings/perl-piped/
+%{__perl} Makefile.PL INSTALLDIRS=vendor
+%{__perl} -pi.orig -e 's|/lib/perl|/%{_lib}/perl|g' Makefile
+popd
+
+%{__make} %{?_smp_mflags}
+
+# Fix @perl@ and @PERL@
+find examples/ -type f \
+    -exec %{__perl} -pi -e 's|^#! \@perl\@|#!%{__perl}|gi' {} \;
+find examples/ -name "*.pl" \
+    -exec %{__perl} -pi -e 's|\015||gi' {} \;
 
 %install
-rm -rf %{buildroot}
-%makeinstall
-
-# Install the font
-mkdir -p %{buildroot}%{_datadir}/fonts
-install -m 644 src/VeraMono.ttf %{buildroot}%{deffont}
-
-# Fix up the documentation
-[ -d docs ] && mv docs docs.src
-mv %{buildroot}/usr/doc docs
-rm -f docs/*.pod
-[ -d examples ] && mv examples examples.src
-mv %{buildroot}/usr/examples examples
-[ -d html ] && mv html html.src
-mv %{buildroot}/usr/html html
-
-# Fix up the perl
-%define perlsite %(perl -MConfig -e 'print $Config{"installsitearch"}')
-mkdir -p %{buildroot}%{perlsite}
-mv %{buildroot}%{_libdir}/perl/* %{buildroot}%{perlsite}
-rmdir %{buildroot}%{_libdir}/perl
-rm -f %{buildroot}/%{perlsite}/auto/RRDs/RRDs.bs
-
-# Fix up the man pages
-if [ "%{_mandir}" != "/usr/share/man" ]; then
-       mkdir -p %{buildroot}%{_mandir}
-       mv %{buildroot}/usr/man/* %{buildroot}%{_mandir}/
-fi
-
-%post
-/sbin/ldconfig
-
-%postun
-/sbin/ldconfig
+rm -rf $RPM_BUILD_ROOT
+make DESTDIR="$RPM_BUILD_ROOT" install
+
+# Pesky RRDp.pm...
+%{__mv} $RPM_BUILD_ROOT%{perl_vendorarch}/../RRDp.pm $RPM_BUILD_ROOT%{perl_vendorarch}/
+
+# We only want .txt and .html files for the main documentation
+%{__mkdir_p} doc2/html doc2/txt
+%{__cp} -a doc/*.txt doc2/txt/
+%{__cp} -a doc/*.html doc2/html/
+
+# Put perl docs in perl package
+%{__mkdir_p} doc3/html
+%{__mv} doc2/html/RRD*.html doc3/html/
+
+# Clean up the examples
+%{__rm} -f examples/Makefile* examples/*.in
+
+# This is so rpm doesn't pick up perl module dependencies automatically
+find examples/ -type f -exec chmod 0644 {} \;
+
+# Clean up the buildroot
+%{__rm} -rf $RPM_BUILD_ROOT%{_datadir}/doc/%{name}-%{version}/{txt,html}/ \
+       $RPM_BUILD_ROOT%{perl_vendorarch}/ntmake.pl \
+       $RPM_BUILD_ROOT%{perl_archlib}/perllocal.pod \
+        $RPM_BUILD_ROOT%{_datadir}/%{name}/examples \
+        $RPM_BUILD_ROOT%{perl_vendorarch}/auto/*/{.packlist,*.bs}
 
 %clean
-rm -rf %{buildroot}
+%{__rm} -rf $RPM_BUILD_ROOT
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
 
 %files
-%defattr (-, root, root)
-%doc 00README CONTRIBUTORS COPYING COPYRIGHT NEWS PROJECTS
-%doc README THREADS TODO
-%doc docs/[a-z]* html/[a-z]*
-%doc examples/*.cgi
-%{_bindir}/rrdcgi
-%{_bindir}/rrdtool
-%{_bindir}/rrdupdate
-%{_libdir}/librrd.so.%{sover}
-%{_libdir}/librrd_th.so.%{sover}
-%{_mandir}/man1/[a-z]*
-%{deffont}
+%{_bindir}/*
+%{_libdir}/*.so.*
+%{_libdir}/rrdtool/*
+%{_datadir}/%{name}/fonts/*
+%{_mandir}/man1/*
 
 %files devel
-%defattr (-, root, root)
-%{_includedir}/rrd.h
-%{_libdir}/librrd.a
-%{_libdir}/librrd.la
-%{_libdir}/librrd.so
-%{_libdir}/librrd_th.a
-%{_libdir}/librrd_th.la
-%{_libdir}/librrd_th.so
-
-%files perl
-%doc examples/*.pl
-%doc docs/RRD* html/RRD*
-%defattr (-, root, root)
-%{perlsite}/RRDp.pm
-%{perlsite}/RRDs.pm
-%dir %{perlsite}/auto/RRDs
-%{perlsite}/auto/RRDs/RRDs.so
-%{_mandir}/man1/RRDp.1*
-%{_mandir}/man1/RRDs.1*
+%defattr(-,root,root,-)
+%{_includedir}/*.h
+%exclude %{_libdir}/*.la
+%{_libdir}/*.so
+
+%files doc
+%defattr(-,root,root,-)
+%doc CHANGES CONTRIBUTORS COPYING COPYRIGHT README TODO NEWS THREADS doc2/html doc2/txt
+%doc examples
+
+%files -n perl-%{name}
+%defattr(-,root,root,-)
+%doc doc3/html
+%{_mandir}/man3/*
+%{perl_vendorarch}/*.pm
+%attr(0755,root,root) %{perl_vendorarch}/auto/RRDs/*
+
+%files -n python-%{name}
+%defattr(-,root,root,-)
+%doc bindings/python/AUTHORS bindings/python/COPYING bindings/python/README
+%{python_sitearch}/rrdtoolmodule.so
 
 %changelog
-* Wed May 26 2004 Mike Slifcak <slif@bellsouth.net> 1.1.0-0.1.20040526
-- package examples with rrdtool-perl (decouple Perl from main package)
-* Thu Apr 29 2004 Chris Adams <cmadams@hiwaay.net> 1.1.0-0.1.20040430
-- initial build
+* Mon Jun 05 2006 Jarod Wilson <jwilson@redhat.com> 1.2.13-3
+- Merge spec fixes from bz 185909
+
+* Sun Jun 04 2006 Jarod Wilson <jwilson@redhat.com> 1.2.13-2
+- Remove explicit perl dep, version grabbing using rpm during
+  rpmbuild not guaranteed to work (fails on ppc in plague),
+  and auto-gen perl deps are sufficient
+
+* Sat Jun 03 2006 Jarod Wilson <jwilson@redhat.com> 1.2.13-1
+- Update to release 1.2.13
+- Merge spec changes from dag, atrpms and mdk builds
+- Additional hacktastic contortions for lib64 & rpath messiness
+- Add missing post/postun ldconfig
+- Fix a bunch of rpmlint errors
+- Disable static libs, per FE guidelines
+- Split off docs
+
+* Wed Apr 19 2006 Chris Ricker <kaboom@oobleck.net> 1.2.12-1
+- Rev to 1.2
+
+* Fri May 20 2005 Matthias Saou <http://freshrpms.net/> 1.0.49-5
+- Include patch from Michael to fix perl module compilation on FC4 (#156242).
+
+* Fri May 20 2005 Matthias Saou <http://freshrpms.net/> 1.0.49-4
+- Fix for the php module patch (Joe Pruett, Dag Wieers), #156716.
+- Update source URL to new location since 1.2 is now the default stable.
+- Don't (yet) update to 1.0.50, as it introduces some changes in the perl
+  modules install.
+
+* Mon Jan 31 2005 Matthias Saou <http://freshrpms.net/> 1.0.49-3
+- Put perl modules in vendor_perl and not site_perl. #146513
+
+* Thu Jan 13 2005 Matthias Saou <http://freshrpms.net/> 1.0.49-2
+- Minor cleanups.
+
+* Thu Aug 25 2004 Dag Wieers <dag@wieers.com> - 1.0.49-1
+- Updated to release 1.0.49.
+
+* Wed Aug 25 2004 Dag Wieers <dag@wieers.com> - 1.0.48-3
+- Fixes for x86_64. (Garrick Staples)
+
+* Fri Jul  2 2004 Matthias Saou <http://freshrpms.net/> 1.0.48-3
+- Actually apply the patch for fixing the php module, doh!
+
+* Thu May 27 2004 Matthias Saou <http://freshrpms.net/> 1.0.48-2
+- Added php.d config entry to load the module once installed.
+
+* Thu May 13 2004 Dag Wieers <dag@wieers.com> - 1.0.48-1
+- Updated to release 1.0.48.
+
+* Tue Apr 06 2004 Dag Wieers <dag@wieers.com> - 1.0.47-1
+- Updated to release 1.0.47.
+
+* Thu Mar  4 2004 Matthias Saou <http://freshrpms.net/> 1.0.46-2
+- Change the strict dependency on perl to fix problem with the recent
+  update.
+
+* Mon Jan  5 2004 Matthias Saou <http://freshrpms.net/> 1.0.46-1
+- Update to 1.0.46.
+- Use system libpng and zlib instead of bundled ones.
+- Added php-rrdtool sub-package for the php4 module.
+
+* Fri Dec  5 2003 Matthias Saou <http://freshrpms.net/> 1.0.45-4
+- Added epoch to the perl dependency to work with rpm > 4.2.
+- Fixed the %% escaping in the perl dep.
+
+* Mon Nov 17 2003 Matthias Saou <http://freshrpms.net/> 1.0.45-2
+- Rebuild for Fedora Core 1.
+
+* Sun Aug  3 2003 Matthias Saou <http://freshrpms.net/>
+- Update to 1.0.45.
+
+* Wed Apr 16 2003 Matthias Saou <http://freshrpms.net/>
+- Update to 1.0.42.
+
+* Mon Mar 31 2003 Matthias Saou <http://freshrpms.net/>
+- Rebuilt for Red Hat Linux 9.
+
+* Wed Mar  5 2003 Matthias Saou <http://freshrpms.net/>
+- Added explicit perl version dependency.
+
+* Sun Feb 23 2003 Matthias Saou <http://freshrpms.net/>
+- Update to 1.0.41.
+
+* Fri Jan 31 2003 Matthias Saou <http://freshrpms.net/>
+- Update to 1.0.40.
+- Spec file cleanup.
+
+* Fri Jul 05 2002 Henri Gomez <hgomez@users.sourceforge.net>
+- 1.0.39
+
+* Mon Jun 03 2002 Henri Gomez <hgomez@users.sourceforge.net>
+- 1.0.38
+
+* Fri Apr 19 2002 Henri Gomez <hgomez@users.sourceforge.net>
+- 1.0.37
+
+* Tue Mar 12 2002 Henri Gomez <hgomez@users.sourceforge.net>
+- 1.0.34
+- rrdtools include zlib 1.1.4 which fix vulnerabilities in 1.1.3
+
diff --git a/src/DejaVuSansMono-Roman.ttf b/src/DejaVuSansMono-Roman.ttf
new file mode 100644 (file)
index 0000000..691c8d6
Binary files /dev/null and b/src/DejaVuSansMono-Roman.ttf differ
index 85aad4e1052181253e4faf0ccf162cfd474ceb92..5ed0558d02444018d94ce542a548f9c0b7bc241c 100644 (file)
 #
 #ACLOCAL_M4       = $(top_srcdir)/config/aclocal.m4
 #AUTOHEADER = @AUTOHEADER@ --localdir=$(top_srcdir)/config
-DEFS += -DMAKE_TIMESTAMP=\""$(shell date)"\"
 fontsdir =  $(datadir)/rrdtool/fonts
-fonts_DATA = VeraMono.ttf
+fonts_DATA = DejaVuSansMono-Roman.ttf
 
-#INCLUDES = $(CGI_INCLUDES) $(FREETYPE_INCLUDES) $(ART_INCLUDES) \
+#INCLUDES = $(FREETYPE_INCLUDES) $(ART_INCLUDES) \
 #           $(PNG_INCLUDES) $(ZLIB_INCLUDES)
-AM_CPPFLAGS = -DRRD_DEFAULT_FONT=\"$(fontsdir)/$(fonts_DATA)\"
+RRD_DEFAULT_FONT=@RRD_DEFAULT_FONT@
+AM_CPPFLAGS = -DRRD_DEFAULT_FONT=\"$(RRD_DEFAULT_FONT)\" -DNUMVERS=@NUMVERS@
 
-RRD_C_FILES =          \
-       getopt.c        \
-       getopt1.c       \
+UPD_C_FILES =          \
+       rrd_getopt.c    \
+       rrd_getopt1.c   \
        parsetime.c     \
-       hash_32.c       \
        rrd_hw.c        \
-       pngsize.c       \
-       rrd_create.c    \
        rrd_diff.c      \
-       rrd_dump.c      \
+       rrd_format.c    \
        rrd_info.c      \
        rrd_error.c     \
+       rrd_open.c      \
+       rrd_nan_inf.c   \
+       rrd_rpncalc.c   \
+       rrd_update.c
+
+RRD_C_FILES =          \
+       hash_32.c       \
+       pngsize.c       \
+       rrd_create.c    \
+       rrd_dump.c      \
        rrd_fetch.c     \
-       rrd_format.c    \
        rrd_graph.c     \
        rrd_graph_helper.c      \
        rrd_last.c      \
+       rrd_lastupdate.c        \
        rrd_first.c     \
-       rrd_open.c      \
        rrd_resize.c    \
        rrd_restore.c   \
-       rrd_rpncalc.c \
        rrd_tune.c      \
-       rrd_update.c    \
+       rrd_version.c   \
        rrd_xport.c     \
-       rrd_nan_inf.c   \
-       rrd_gfx.c rrd_gfx.h \
+        art_rgba_svp.c \
+       rrd_gfx.c \
        rrd_afm.c rrd_afm_data.c \
-       getopt.h parsetime.h \
+       rrd_tool.c
+
+noinst_HEADERS = \
+        art_rgba_svp.h \
+       unused.h \
+       rrd_gfx.h \
+       rrd_getopt.h parsetime.h \
        rrd_format.h rrd_tool.h rrd_xport.h rrd.h rrd_hw.h rrd_rpncalc.h \
-       rrd_tool.c \
        rrd_nan_inf.h fnv.h rrd_graph.h rrd_afm.h rrd_afm_data.h \
        rrd_is_thread_safe.h
 
+noinst_LTLIBRARIES        = librrdupd.la
+
 lib_LTLIBRARIES           = librrd.la 
 if BUILD_MULTITHREAD
 lib_LTLIBRARIES           += librrd_th.la
 endif
 
-#noinst_LTLIBRARIES        = librrd_private.la
+librrdupd_la_SOURCES      = $(UPD_C_FILES) rrd_not_thread_safe.c
+librrdupd_la_LIBADD       = $(CORE_LIBS)
 
-librrd_la_SOURCES         = $(RRD_C_FILES) rrd_not_thread_safe.c
-#librrd_private_la_SOURCES = $(RRD_C_FILES) rrd_not_thread_safe.c
+librrd_la_SOURCES         = $(RRD_C_FILES)
+librrd_la_LIBADD          = librrdupd.la $(ALL_LIBS)
 
-# librrd_la_LIBADD          = $(RRD_LIBS)
+# This flag accepts an argument of the form current[:revision[:age]]. So,
+# passing -version-info 3:12:1 sets current to 3, revision to 12, and age to 1.
+#
+# If either revision or age are omitted, they default to 0. Also note that
+# age must be less than or equal to the current interface number.
+#
+# Here are a set of rules to help you update your library version information:
+#
+#   1. Start with version information of 0:0:0 for each libtool library.
+#
+#   2. Update the version information only immediately before a public
+#   release of your software. More frequent updates are unnecessary, and
+#   only guarantee that the current interface number gets larger faster.
+#
+#   3. If the library source code has changed at all since the last update,
+#   then increment revision (c:r:a becomes c:r+1:a).
+#
+#   4. If any interfaces have been added, removed, or changed since the last
+#   update, increment current, and set revision to 0.
+#
+#   5. If any interfaces have been added since the last public release, then
+#   increment age.
+#
+#   6. If any interfaces have been removed since the last public release,
+#   then set age to 0.
+#
+# Never try to set the interface numbers so that they correspond to the
+# release number of your package. This is an abuse that only fosters
+# misunderstanding of the purpose of library versions. Instead, use the
+# -release flag (see Release numbers), but be warned that every release of
+# your package will not be binary compatible with any other release.
+#
 # see http://www.gnu.org/software/libtool/manual.html#SEC32 for explanation
-librrd_la_LDFLAGS         = -version-info 1:0:0
+librrd_la_LDFLAGS         = -version-info 2:11:0
 
-librrd_th_la_SOURCES         = $(RRD_C_FILES) rrd_thread_safe.c
+librrd_th_la_SOURCES         = $(UPD_C_FILES) $(RRD_C_FILES) rrd_thread_safe.c
 librrd_th_la_CFLAGS          = $(MULTITHREAD_CFLAGS)
-librrd_th_la_LDFLAGS         = $(MULTITHREAD_LDFLAGS) -version-info 1:0:0
-
+librrd_th_la_LDFLAGS         = $(MULTITHREAD_LDFLAGS) -version-info 2:11:0
+librrd_th_la_LIBADD          = $(ALL_LIBS)
 
 include_HEADERS        = rrd.h
 
-#librrd_private_la_LIBADD  = $(RRD_LIBS)
-#librrd_private_la_LDFLAGS = -static
-
 bin_PROGRAMS   = rrdtool rrdupdate
+
 if BUILD_RRDCGI
 bin_PROGRAMS += rrdcgi
 endif
@@ -78,17 +120,15 @@ endif
 rrdcgi_SOURCES = rrd_cgi.c
 rrdcgi_LDADD   = librrd.la
 
-rrdupdate_SOURCES = 
-rrdupdate_LDADD        = rrdupdate.o librrd.la
-
-# rrdupdate.c: rrd_update.c
-#      -ln -s ${srcdir}/rrdupdate.c rrd_update.c
-
-rrdupdate.o: rrd_update.c
-       $(COMPILE) -DSTANDALONE -c -o $@ $^
+rrdupdate_SOURCES = rrdupdate.c
+rrdupdate_LDADD          = librrdupd.la
 
 rrdtool_SOURCES = 
-rrdtool_DEPENDENCIES = rrd_tool.o
+rrdtool_DEPENDENCIES = rrd_tool.o librrd.la
 rrdtool_LDADD  = librrd.la
 
-EXTRA_DIST= rrdtool.dsp rrdtool.dsw $(fonts_DATA)
+# strftime is here because we do not usually need it. unices have propper
+# iso date support
+EXTRA_DIST= strftime.c strftime.h $(fonts_DATA) \
+       win32comp.c  rrd_thread_safe_nt.c get_ver.awk
+
index 236056c49e937c730a27f0aae898d56b657e8d6e..139f0b4311ad2e0369a347b3be6c46e6c2b730d5 100644 (file)
Binary files a/src/VeraMono.ttf and b/src/VeraMono.ttf differ
diff --git a/src/art_rgba_svp.c b/src/art_rgba_svp.c
new file mode 100644 (file)
index 0000000..25083d7
--- /dev/null
@@ -0,0 +1,333 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ *  art_rgba_svp.c: A slightly modified version of art_rgb_svp to render into rgba buffer
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public License
+ *  as published by the Free Software Foundation; either version 2 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Authors:
+ *    Raph Levien <raph@acm.org>
+ *    Lauris Kaplinski <lauris@ariman.ee>
+ *
+ *  Copyright (C) 1998 Raph Levien
+ *
+ */
+
+#define SP_ART_RGBA_SVP_C
+
+/* Render a sorted vector path into an RGBA buffer. */
+
+#include <libart_lgpl/art_misc.h>
+#include <libart_lgpl/art_svp.h>
+#include <libart_lgpl/art_svp_render_aa.h>
+#include <libart_lgpl/art_rgb.h>
+
+#include "art_rgba_svp.h"
+#include "unused.h"
+
+static void art_rgba_fill_run (art_u8 * linebuf, art_u8 r, art_u8 g, art_u8 b, int n);
+static void art_rgba_run_alpha (art_u8 * linebuf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n);
+
+typedef struct _ArtRgbaSVPAlphaData ArtRgbaSVPAlphaData;
+
+struct _ArtRgbaSVPAlphaData {
+  int alphatab[256];
+  art_u8 r, g, b, alpha;
+  art_u8 *buf;
+  int rowstride;
+  int libart_x0, libart_x1;
+};
+
+static void
+art_rgba_svp_alpha_callback (void *callback_data, int UNUSED(y),
+                           int start, ArtSVPRenderAAStep *steps, int n_steps)
+{
+  ArtRgbaSVPAlphaData *data = callback_data;
+  art_u8 *linebuf;
+  int run_x0, run_x1;
+  art_u32 running_sum = start;
+  int libart_x0, libart_x1;
+  int k;
+  art_u8 r, g, b;
+  int *alphatab;
+  int alpha;
+
+  linebuf = data->buf;
+  libart_x0 = data->libart_x0;
+  libart_x1 = data->libart_x1;
+
+  r = data->r;
+  g = data->g;
+  b = data->b;
+  alphatab = data->alphatab;
+
+  if (n_steps > 0)
+    {
+      run_x1 = steps[0].x;
+      if (run_x1 > libart_x0)
+       {
+         alpha = (running_sum >> 16) & 0xff;
+         if (alpha)
+           art_rgba_run_alpha (linebuf,
+                              r, g, b, alphatab[alpha],
+                              run_x1 - libart_x0);
+       }
+
+      /* render the steps into tmpbuf */
+      for (k = 0; k < n_steps - 1; k++)
+       {
+         running_sum += steps[k].delta;
+         run_x0 = run_x1;
+         run_x1 = steps[k + 1].x;
+         if (run_x1 > run_x0)
+           {
+             alpha = (running_sum >> 16) & 0xff;
+             if (alpha)
+               art_rgba_run_alpha (linebuf + (run_x0 - libart_x0) * 4,
+                                  r, g, b, alphatab[alpha],
+                                  run_x1 - run_x0);
+           }
+       }
+      running_sum += steps[k].delta;
+      if (libart_x1 > run_x1)
+       {
+         alpha = (running_sum >> 16) & 0xff;
+         if (alpha)
+           art_rgba_run_alpha (linebuf + (run_x1 - libart_x0) * 4,
+                              r, g, b, alphatab[alpha],
+                              libart_x1 - run_x1);
+       }
+    }
+  else
+    {
+      alpha = (running_sum >> 16) & 0xff;
+      if (alpha)
+       art_rgba_run_alpha (linebuf,
+                          r, g, b, alphatab[alpha],
+                          libart_x1 - libart_x0);
+    }
+
+  data->buf += data->rowstride;
+}
+
+static void
+art_rgba_svp_alpha_opaque_callback (void *callback_data, int UNUSED(y),
+                                  int start,
+                                  ArtSVPRenderAAStep *steps, int n_steps)
+{
+  ArtRgbaSVPAlphaData *data = callback_data;
+  art_u8 *linebuf;
+  int run_x0, run_x1;
+  art_u32 running_sum = start;
+  int libart_x0, libart_x1;
+  int k;
+  art_u8 r, g, b;
+  int *alphatab;
+  int alpha;
+
+  linebuf = data->buf;
+  libart_x0 = data->libart_x0;
+  libart_x1 = data->libart_x1;
+
+  r = data->r;
+  g = data->g;
+  b = data->b;
+  alphatab = data->alphatab;
+
+  if (n_steps > 0)
+    {
+      run_x1 = steps[0].x;
+      if (run_x1 > libart_x0)
+       {
+         alpha = running_sum >> 16;
+         if (alpha)
+           {
+             if (alpha >= 255)
+               art_rgba_fill_run (linebuf,
+                                 r, g, b,
+                                 run_x1 - libart_x0);
+             else
+               art_rgba_run_alpha (linebuf,
+                                  r, g, b, alphatab[alpha],
+                                  run_x1 - libart_x0);
+           }
+       }
+
+      /* render the steps into tmpbuf */
+      for (k = 0; k < n_steps - 1; k++)
+       {
+         running_sum += steps[k].delta;
+         run_x0 = run_x1;
+         run_x1 = steps[k + 1].x;
+         if (run_x1 > run_x0)
+           {
+             alpha = running_sum >> 16;
+             if (alpha)
+               {
+                 if (alpha >= 255)
+                   art_rgba_fill_run (linebuf + (run_x0 - libart_x0) * 4,
+                                     r, g, b,
+                                     run_x1 - run_x0);
+                 else
+                   art_rgba_run_alpha (linebuf + (run_x0 - libart_x0) * 4,
+                                      r, g, b, alphatab[alpha],
+                                      run_x1 - run_x0);
+               }
+           }
+       }
+      running_sum += steps[k].delta;
+      if (libart_x1 > run_x1)
+       {
+         alpha = running_sum >> 16;
+         if (alpha)
+           {
+             if (alpha >= 255)
+               art_rgba_fill_run (linebuf + (run_x1 - libart_x0) * 4,
+                                 r, g, b,
+                                 libart_x1 - run_x1);
+             else
+               art_rgba_run_alpha (linebuf + (run_x1 - libart_x0) * 4,
+                                  r, g, b, alphatab[alpha],
+                                  libart_x1 - run_x1);
+           }
+       }
+    }
+  else
+    {
+      alpha = running_sum >> 16;
+      if (alpha)
+       {
+         if (alpha >= 255)
+           art_rgba_fill_run (linebuf,
+                             r, g, b,
+                             libart_x1 - libart_x0);
+         else
+           art_rgba_run_alpha (linebuf,
+                              r, g, b, alphatab[alpha],
+                              libart_x1 - libart_x0);
+       }
+    }
+
+  data->buf += data->rowstride;
+}
+
+/**
+ * gnome_print_art_rgba_svp_alpha: Alpha-composite sorted vector path over RGBA buffer.
+ * @svp: The source sorted vector path.
+ * @libart_x0: Left coordinate of destination rectangle.
+ * @libart_y0: Top coordinate of destination rectangle.
+ * @libart_x1: Right coordinate of destination rectangle.
+ * @libart_y1: Bottom coordinate of destination rectangle.
+ * @rgba: Color in 0xRRGGBBAA format.
+ * @buf: Destination RGB buffer.
+ * @rowstride: Rowstride of @buf buffer.
+ * @alphagamma: #ArtAlphaGamma for gamma-correcting the compositing.
+ *
+ * Renders the shape specified with @svp over the @buf RGB buffer.
+ * @libart_x1 - @x0 specifies the width, and @libart_y1 - @libart_y0 specifies the height,
+ * of the rectangle rendered. The new pixels are stored starting at
+ * the first byte of @buf. Thus, the @x0 and @libart_y0 parameters specify
+ * an offset within @svp, and may be tweaked as a way of doing
+ * integer-pixel translations without fiddling with @svp itself.
+ *
+ * The @rgba argument specifies the color for the rendering. Pixels of
+ * entirely 0 winding number are left untouched. Pixels of entirely
+ * 1 winding number have the color @rgba composited over them (ie,
+ * are replaced by the red, green, blue components of @rgba if the alpha
+ * component is 0xff). Pixels of intermediate coverage are interpolated
+ * according to the rule in @alphagamma, or default to linear if
+ * @alphagamma is NULL.
+ **/
+void
+gnome_print_art_rgba_svp_alpha (const ArtSVP *svp,
+                               int libart_x0, int libart_y0, int libart_x1, int libart_y1,
+                               art_u32 rgba,
+                               art_u8 *buf, int rowstride,
+                               ArtAlphaGamma UNUSED(*alphagamma))
+{
+  ArtRgbaSVPAlphaData data;
+  int r, g, b, alpha;
+  int i;
+  int a, da;
+
+  r = rgba >> 24;
+  g = (rgba >> 16) & 0xff;
+  b = (rgba >> 8) & 0xff;
+  alpha = rgba & 0xff;
+
+  data.r = r;
+  data.g = g;
+  data.b = b;
+  data.alpha = alpha;
+
+  a = 0x8000;
+  da = (alpha * 66051 + 0x80) >> 8; /* 66051 equals 2 ^ 32 / (255 * 255) */
+
+  for (i = 0; i < 256; i++)
+    {
+      data.alphatab[i] = a >> 16;
+      a += da;
+    }
+
+  data.buf = buf;
+  data.rowstride = rowstride;
+  data.libart_x0 = libart_x0;
+  data.libart_x1 = libart_x1;
+  if (alpha == 255)
+    art_svp_render_aa (svp, libart_x0, libart_y0, libart_x1, libart_y1, art_rgba_svp_alpha_opaque_callback,
+                      &data);
+  else
+    art_svp_render_aa (svp, libart_x0, libart_y0, libart_x1, libart_y1, art_rgba_svp_alpha_callback, &data);
+}
+
+static void
+art_rgba_fill_run (art_u8 * buf, art_u8 r, art_u8 g, art_u8 b, int n)
+{
+       int i;
+
+       for (i = 0; i < n; i++) {
+               * buf++ = r;
+               * buf++ = g;
+               * buf++ = b;
+               * buf++ = 255;
+       }
+}
+
+/* fixme: this */
+
+static void
+art_rgba_run_alpha (art_u8 * buf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n)
+{
+       int i;
+       int br, bg, bb, ba;
+       int cr, cg, cb;
+
+       for (i = 0; i < n; i++) {
+               br = * (buf + 0);
+               bg = * (buf + 1);
+               bb = * (buf + 2);
+               ba = * (buf + 3);
+
+               cr = (br * ba + 0x80) >> 8;
+               cg = (bg * ba + 0x80) >> 8;
+               cb = (bb * ba + 0x80) >> 8;
+
+               * buf++ = cr + (((r - cr) * alpha + 0x80) >> 8);
+               * buf++ = cg + (((g - cg) * alpha + 0x80) >> 8);
+               * buf++ = cb + (((b - cb) * alpha + 0x80) >> 8);
+               * buf++ = ba + (((255 - ba) * alpha + 0x80) >> 8);
+       }
+}
+
+
diff --git a/src/art_rgba_svp.h b/src/art_rgba_svp.h
new file mode 100644 (file)
index 0000000..4cac175
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef SP_ART_RGBA_SVP_H
+#define SP_ART_RGBA_SVP_H
+
+#include <libart_lgpl/art_misc.h>
+#include <libart_lgpl/art_alphagamma.h>
+#include <libart_lgpl/art_affine.h>
+#include <libart_lgpl/art_svp.h>
+#include <libart_lgpl/art_uta.h>
+
+void
+gnome_print_art_rgba_svp_alpha (const ArtSVP *svp,
+                               int x0, int y0, int x1, int y1,
+                               art_u32 rgba,
+                               art_u8 *buf, int rowstride,
+                               ArtAlphaGamma *alphagamma);
+
+#endif /* SP_ART_RGBA_SVP_H */
index 22f6ff69fc7aa647bf6d3e025ad5ab605883752c..e69f9cee1af9ec9f1da41d5aaf45d1df38773c73 100644 (file)
--- a/src/fnv.h
+++ b/src/fnv.h
@@ -99,10 +99,10 @@ typedef unsigned long Fnv32_t;
  */
 #define FNV1_32_INIT ((Fnv32_t)0x811c9dc5)
 
-Fnv32_t fnv_32_buf(void *, size_t, Fnv32_t);
+Fnv32_t fnv_32_buf(const void *, size_t, Fnv32_t);
 
-Fnv32_t fnv_32_str(char *, Fnv32_t );
+Fnv32_t fnv_32_str(const char *, Fnv32_t );
 
-unsigned long FnvHash(char *);
+unsigned long FnvHash(const char *);
 
 #endif /* __FNV_H__ */
index 24c659131c9d9cc9ec31c91ece447001ebcb8714..99e7db643f4caf6eca077540d17c421eaab38e75 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * gdpng.c  add PNG output routine to gd library
  *****************************************************************************/
diff --git a/src/get_ver.awk b/src/get_ver.awk
new file mode 100644 (file)
index 0000000..e8c4552
--- /dev/null
@@ -0,0 +1,40 @@
+# ****************************************************************************
+# RRDtool 1.2.19  Copyright by Tobi Oetiker, 1997-2007
+# ****************************************************************************
+# get_ver.awk   AWK Script for non-configure builds
+# ****************************************************************************
+# $Id: get_ver.awk 1000 2007-14-02 05:51:34Z oetiker $
+# ****************************************************************************
+BEGIN {
+  # fetch rrdtool version number from input file and write them to STDOUT
+  while ((getline < ARGV[1]) > 0) {
+    if (match ($0, /^AC_INIT/)) {
+      split($1, t, ",");
+      my_ver_str = substr(t[2],2,length(t[2])-3);
+      split(my_ver_str, v, ".");
+      gsub("[^0-9].*$", "", v[3]);
+      my_ver = v[1] "," v[2] "," v[3];
+    }
+    if (match ($0, /^NUMVERS=/)) {
+      split($1, t, "=");
+      my_ver_num = t[2];
+    }
+  }
+  # read from from input file, replace placeholders, and write to STDOUT
+  if (ARGV[2]) {
+    while ((getline < ARGV[2]) > 0) {
+      if (match ($0, /@@NUMVERS@@/)) {
+        gsub("@@NUMVERS@@", my_ver_num, $0);
+      }
+      if (match ($0, /@@PACKAGE_VERSION@@/)) {
+        gsub("@@PACKAGE_VERSION@@", "" my_ver_str "", $0);
+      }
+      print;
+    }
+  } else {
+    print "RRD_VERSION = " my_ver "";
+    print "RRD_VERSION_STR = " my_ver_str "";
+    print "RRD_NUMVERS = " my_ver_num "";
+  }
+}
+
diff --git a/src/getopt.c b/src/getopt.c
deleted file mode 100644 (file)
index 81a8e89..0000000
+++ /dev/null
@@ -1,1002 +0,0 @@
-/* Getopt for GNU.
-   NOTE: getopt is now part of the C library, so if you don't know what
-   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
-   before changing it!
-
-   Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97
-   Free Software Foundation, Inc.
-
-   This file is part of the GNU C Library.  Its master source is NOT part of
-   the C library, however.  The master source lives in /gd/gnu/lib.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-\f
-/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
-   Ditto for AIX 3.2 and <stdlib.h>.  */
-#ifndef _NO_PROTO
-#define _NO_PROTO
-#endif
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#if !defined (__STDC__) || !__STDC__
-/* This is a separate conditional since some stdc systems
-   reject `defined (const)'.  */
-#ifndef const
-#define const
-#endif
-#endif
-
-#include <stdio.h>
-
-/* Comment out all this code if we are using the GNU C Library, and are not
-   actually compiling the library itself.  This code is part of the GNU C
-   Library, but also included in many other GNU distributions.  Compiling
-   and linking in this code is a waste when using the GNU C library
-   (especially if it is a shared library).  Rather than having every GNU
-   program understand `configure --with-gnu-libc' and omit the object files,
-   it is simpler to just do this in the source for each such file.  */
-
-#define GETOPT_INTERFACE_VERSION 2
-#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
-#include <gnu-versions.h>
-#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
-#define ELIDE_CODE
-#endif
-#endif
-
-#ifndef ELIDE_CODE
-
-
-/* This needs to come after some library #include
-   to get __GNU_LIBRARY__ defined.  */
-#ifdef __GNU_LIBRARY__
-/* Don't include stdlib.h for non-GNU C libraries because some of them
-   contain conflicting prototypes for getopt.  */
-#include <stdlib.h>
-#include <unistd.h>
-#endif /* GNU C library.  */
-
-#ifdef VMS
-#include <unixlib.h>
-#if HAVE_STRING_H - 0
-#include <string.h>
-#endif
-#endif
-
-#if defined (WIN32) && !defined (__CYGWIN32__)
-/* It's not Unix, really.  See?  Capital letters.  */
-#include <windows.h>
-#define getpid() GetCurrentProcessId()
-#endif
-
-#ifndef _
-/* This is for other GNU distributions with internationalized messages.
-   When compiling libc, the _ macro is predefined.  */
-#ifdef HAVE_LIBINTL_H
-# include <libintl.h>
-# define _(msgid)      gettext (msgid)
-#else
-# define _(msgid)      (msgid)
-#endif
-#endif
-
-/* This version of `getopt' appears to the caller like standard Unix `getopt'
-   but it behaves differently for the user, since it allows the user
-   to intersperse the options with the other arguments.
-
-   As `getopt' works, it permutes the elements of ARGV so that,
-   when it is done, all the options precede everything else.  Thus
-   all application programs are extended to handle flexible argument order.
-
-   Setting the environment variable POSIXLY_CORRECT disables permutation.
-   Then the behavior is completely standard.
-
-   GNU application programs can use a third alternative mode in which
-   they can distinguish the relative order of options and other arguments.  */
-
-#include "getopt.h"
-
-/* For communication from `getopt' to the caller.
-   When `getopt' finds an option that takes an argument,
-   the argument value is returned here.
-   Also, when `ordering' is RETURN_IN_ORDER,
-   each non-option ARGV-element is returned here.  */
-
-char *optarg = NULL;
-
-/* Index in ARGV of the next element to be scanned.
-   This is used for communication to and from the caller
-   and for communication between successive calls to `getopt'.
-
-   On entry to `getopt', zero means this is the first call; initialize.
-
-   When `getopt' returns -1, this is the index of the first of the
-   non-option elements that the caller should itself scan.
-
-   Otherwise, `optind' communicates from one call to the next
-   how much of ARGV has been scanned so far.  */
-
-/* 1003.2 says this must be 1 before any call.  */
-int optind = 1;
-
-/* Formerly, initialization of getopt depended on optind==0, which
-   causes problems with re-calling getopt as programs generally don't
-   know that. */
-
-int __getopt_initialized = 0;
-
-/* The next char to be scanned in the option-element
-   in which the last option character we returned was found.
-   This allows us to pick up the scan where we left off.
-
-   If this is zero, or a null string, it means resume the scan
-   by advancing to the next ARGV-element.  */
-
-static char *nextchar;
-
-/* Callers store zero here to inhibit the error message
-   for unrecognized options.  */
-
-int opterr = 1;
-
-/* Set to an option character which was unrecognized.
-   This must be initialized on some systems to avoid linking in the
-   system's own getopt implementation.  */
-
-int optopt = '?';
-
-/* Describe how to deal with options that follow non-option ARGV-elements.
-
-   If the caller did not specify anything,
-   the default is REQUIRE_ORDER if the environment variable
-   POSIXLY_CORRECT is defined, PERMUTE otherwise.
-
-   REQUIRE_ORDER means don't recognize them as options;
-   stop option processing when the first non-option is seen.
-   This is what Unix does.
-   This mode of operation is selected by either setting the environment
-   variable POSIXLY_CORRECT, or using `+' as the first character
-   of the list of option characters.
-
-   PERMUTE is the default.  We permute the contents of ARGV as we scan,
-   so that eventually all the non-options are at the end.  This allows options
-   to be given in any order, even with programs that were not written to
-   expect this.
-
-   RETURN_IN_ORDER is an option available to programs that were written
-   to expect options and other ARGV-elements in any order and that care about
-   the ordering of the two.  We describe each non-option ARGV-element
-   as if it were the argument of an option with character code 1.
-   Using `-' as the first character of the list of option characters
-   selects this mode of operation.
-
-   The special argument `--' forces an end of option-scanning regardless
-   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
-   `--' can cause `getopt' to return -1 with `optind' != ARGC.  */
-
-static enum
-{
-  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
-} ordering;
-
-/* Value of POSIXLY_CORRECT environment variable.  */
-static char *posixly_correct;
-\f
-/* we must include string as there are warnings without it ... */
-#include <string.h>
-
-#ifdef __GNU_LIBRARY__
-/* We want to avoid inclusion of string.h with non-GNU libraries
-   because there are many ways it can cause trouble.
-   On some systems, it contains special magic macros that don't work
-   in GCC.  */
-#define        my_index        strchr
-#else
-
-/* Avoid depending on library functions or files
-   whose names are inconsistent.  */
-
-char *getenv ();
-
-static char *
-my_index (str, chr)
-     const char *str;
-     int chr;
-{
-  while (*str)
-    {
-      if (*str == chr)
-       return (char *) str;
-      str++;
-    }
-  return 0;
-}
-
-/* If using GCC, we can safely declare strlen this way.
-   If not using GCC, it is ok not to declare it.  */
-#ifdef __GNUC__
-/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
-   That was relevant to code that was here before.  */
-#if !defined (__STDC__) || !__STDC__
-/* gcc with -traditional declares the built-in strlen to return int,
-   and has done so at least since version 2.4.5. -- rms.  */
-extern int strlen (const char *);
-#endif /* not __STDC__ */
-#endif /* __GNUC__ */
-
-#endif /* not __GNU_LIBRARY__ */
-\f
-/* Handle permutation of arguments.  */
-
-/* Describe the part of ARGV that contains non-options that have
-   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
-   `last_nonopt' is the index after the last of them.  */
-
-static int first_nonopt;
-static int last_nonopt;
-
-#ifdef _LIBC
-/* Bash 2.0 gives us an environment variable containing flags
-   indicating ARGV elements that should not be considered arguments.  */
-
-static const char *nonoption_flags;
-static int nonoption_flags_len;
-
-static int original_argc;
-static char *const *original_argv;
-
-/* Make sure the environment variable bash 2.0 puts in the environment
-   is valid for the getopt call we must make sure that the ARGV passed
-   to getopt is that one passed to the process.  */
-static void store_args (int argc, char *const *argv) __attribute__ ((unused));
-static void
-store_args (int argc, char *const *argv)
-{
-  /* XXX This is no good solution.  We should rather copy the args so
-     that we can compare them later.  But we must not use malloc(3).  */
-  original_argc = argc;
-  original_argv = argv;
-}
-text_set_element (__libc_subinit, store_args);
-#endif
-
-/* Exchange two adjacent subsequences of ARGV.
-   One subsequence is elements [first_nonopt,last_nonopt)
-   which contains all the non-options that have been skipped so far.
-   The other is elements [last_nonopt,optind), which contains all
-   the options processed since those non-options were skipped.
-
-   `first_nonopt' and `last_nonopt' are relocated so that they describe
-   the new indices of the non-options in ARGV after they are moved.  */
-
-#if defined (__STDC__) && __STDC__
-static void exchange (char **);
-#endif
-
-static void
-exchange (argv)
-     char **argv;
-{
-  int bottom = first_nonopt;
-  int middle = last_nonopt;
-  int top = optind;
-  char *tem;
-
-  /* Exchange the shorter segment with the far end of the longer segment.
-     That puts the shorter segment into the right place.
-     It leaves the longer segment in the right place overall,
-     but it consists of two parts that need to be swapped next.  */
-
-  while (top > middle && middle > bottom)
-    {
-      if (top - middle > middle - bottom)
-       {
-         /* Bottom segment is the short one.  */
-         int len = middle - bottom;
-         register int i;
-
-         /* Swap it with the top part of the top segment.  */
-         for (i = 0; i < len; i++)
-           {
-             tem = argv[bottom + i];
-             argv[bottom + i] = argv[top - (middle - bottom) + i];
-             argv[top - (middle - bottom) + i] = tem;
-           }
-         /* Exclude the moved bottom segment from further swapping.  */
-         top -= len;
-       }
-      else
-       {
-         /* Top segment is the short one.  */
-         int len = top - middle;
-         register int i;
-
-         /* Swap it with the bottom part of the bottom segment.  */
-         for (i = 0; i < len; i++)
-           {
-             tem = argv[bottom + i];
-             argv[bottom + i] = argv[middle + i];
-             argv[middle + i] = tem;
-           }
-         /* Exclude the moved top segment from further swapping.  */
-         bottom += len;
-       }
-    }
-
-  /* Update records for the slots the non-options now occupy.  */
-
-  first_nonopt += (optind - last_nonopt);
-  last_nonopt = optind;
-}
-
-/* Initialize the internal data when the first call is made.  */
-
-#if defined (__STDC__) && __STDC__
-static const char *_getopt_initialize (int, char *const *, const char *);
-#endif
-static const char *
-_getopt_initialize (argc, argv, optstring)
-     int argc;
-     char *const *argv;
-     const char *optstring;
-{
-  /* Start processing options with ARGV-element 1 (since ARGV-element 0
-     is the program name); the sequence of previously skipped
-     non-option ARGV-elements is empty.  */
-
-  first_nonopt = last_nonopt = optind = 1;
-
-  nextchar = NULL;
-
-  posixly_correct = getenv ("POSIXLY_CORRECT");
-
-  /* Determine how to handle the ordering of options and nonoptions.  */
-
-  if (optstring[0] == '-')
-    {
-      ordering = RETURN_IN_ORDER;
-      ++optstring;
-    }
-  else if (optstring[0] == '+')
-    {
-      ordering = REQUIRE_ORDER;
-      ++optstring;
-    }
-  else if (posixly_correct != NULL)
-    ordering = REQUIRE_ORDER;
-  else
-    ordering = PERMUTE;
-
-#ifdef _LIBC
-  if (posixly_correct == NULL
-      && argc == original_argc && argv == original_argv)
-    {
-      /* Bash 2.0 puts a special variable in the environment for each
-        command it runs, specifying which ARGV elements are the results of
-        file name wildcard expansion and therefore should not be
-        considered as options.  */
-      char var[100];
-      sprintf (var, "_%d_GNU_nonoption_argv_flags_", getpid ());
-      nonoption_flags = getenv (var);
-      if (nonoption_flags == NULL)
-       nonoption_flags_len = 0;
-      else
-       nonoption_flags_len = strlen (nonoption_flags);
-    }
-  else
-    nonoption_flags_len = 0;
-#endif
-
-  return optstring;
-}
-\f
-/* Scan elements of ARGV (whose length is ARGC) for option characters
-   given in OPTSTRING.
-
-   If an element of ARGV starts with '-', and is not exactly "-" or "--",
-   then it is an option element.  The characters of this element
-   (aside from the initial '-') are option characters.  If `getopt'
-   is called repeatedly, it returns successively each of the option characters
-   from each of the option elements.
-
-   If `getopt' finds another option character, it returns that character,
-   updating `optind' and `nextchar' so that the next call to `getopt' can
-   resume the scan with the following option character or ARGV-element.
-
-   If there are no more option characters, `getopt' returns -1.
-   Then `optind' is the index in ARGV of the first ARGV-element
-   that is not an option.  (The ARGV-elements have been permuted
-   so that those that are not options now come last.)
-
-   OPTSTRING is a string containing the legitimate option characters.
-   If an option character is seen that is not listed in OPTSTRING,
-   return '?' after printing an error message.  If you set `opterr' to
-   zero, the error message is suppressed but we still return '?'.
-
-   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
-   so the following text in the same ARGV-element, or the text of the following
-   ARGV-element, is returned in `optarg'.  Two colons mean an option that
-   wants an optional arg; if there is text in the current ARGV-element,
-   it is returned in `optarg', otherwise `optarg' is set to zero.
-
-   If OPTSTRING starts with `-' or `+', it requests different methods of
-   handling the non-option ARGV-elements.
-   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
-
-   Long-named options begin with `--' instead of `-'.
-   Their names may be abbreviated as long as the abbreviation is unique
-   or is an exact match for some defined option.  If they have an
-   argument, it follows the option name in the same ARGV-element, separated
-   from the option name by a `=', or else the in next ARGV-element.
-   When `getopt' finds a long-named option, it returns 0 if that option's
-   `flag' field is nonzero, the value of the option's `val' field
-   if the `flag' field is zero.
-
-   The elements of ARGV aren't really const, because we permute them.
-   But we pretend they're const in the prototype to be compatible
-   with other systems.
-
-   LONGOPTS is a vector of `struct option' terminated by an
-   element containing a name which is zero.
-
-   LONGIND returns the index in LONGOPT of the long-named option found.
-   It is only valid when a long-named option has been found by the most
-   recent call.
-
-   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
-   long-named options.  */
-
-int
-_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
-     int argc;
-     char *const *argv;
-     const char *optstring;
-     const struct option *longopts;
-     int *longind;
-     int long_only;
-{
-  optarg = NULL;
-
-  if (!__getopt_initialized || optind == 0)
-    {
-      optstring = _getopt_initialize (argc, argv, optstring);
-      optind = 1;              /* Don't scan ARGV[0], the program name.  */
-      __getopt_initialized = 1;
-    }
-
-  /* Test whether ARGV[optind] points to a non-option argument.
-     Either it does not have option syntax, or there is an environment flag
-     from the shell indicating it is not an option.  The later information
-     is only used when the used in the GNU libc.  */
-#ifdef _LIBC
-#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0'       \
-                    || (optind < nonoption_flags_len                         \
-                        && nonoption_flags[optind] == '1'))
-#else
-#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
-#endif
-
-  if (nextchar == NULL || *nextchar == '\0')
-    {
-      /* Advance to the next ARGV-element.  */
-
-      /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
-        moved back by the user (who may also have changed the arguments).  */
-      if (last_nonopt > optind)
-       last_nonopt = optind;
-      if (first_nonopt > optind)
-       first_nonopt = optind;
-
-      if (ordering == PERMUTE)
-       {
-         /* If we have just processed some options following some non-options,
-            exchange them so that the options come first.  */
-
-         if (first_nonopt != last_nonopt && last_nonopt != optind)
-           exchange ((char **) argv);
-         else if (last_nonopt != optind)
-           first_nonopt = optind;
-
-         /* Skip any additional non-options
-            and extend the range of non-options previously skipped.  */
-
-         while (optind < argc && NONOPTION_P)
-           optind++;
-         last_nonopt = optind;
-       }
-
-      /* The special ARGV-element `--' means premature end of options.
-        Skip it like a null option,
-        then exchange with previous non-options as if it were an option,
-        then skip everything else like a non-option.  */
-
-      if (optind != argc && !strcmp (argv[optind], "--"))
-       {
-         optind++;
-
-         if (first_nonopt != last_nonopt && last_nonopt != optind)
-           exchange ((char **) argv);
-         else if (first_nonopt == last_nonopt)
-           first_nonopt = optind;
-         last_nonopt = argc;
-
-         optind = argc;
-       }
-
-      /* If we have done all the ARGV-elements, stop the scan
-        and back over any non-options that we skipped and permuted.  */
-
-      if (optind == argc)
-       {
-         /* Set the next-arg-index to point at the non-options
-            that we previously skipped, so the caller will digest them.  */
-         if (first_nonopt != last_nonopt)
-           optind = first_nonopt;
-         return -1;
-       }
-
-      /* If we have come to a non-option and did not permute it,
-        either stop the scan or describe it to the caller and pass it by.  */
-
-      if (NONOPTION_P)
-       {
-         if (ordering == REQUIRE_ORDER)
-           return -1;
-         optarg = argv[optind++];
-         return 1;
-       }
-
-      /* We have found another option-ARGV-element.
-        Skip the initial punctuation.  */
-
-      nextchar = (argv[optind] + 1
-                 + (longopts != NULL && argv[optind][1] == '-'));
-    }
-
-  /* Decode the current option-ARGV-element.  */
-
-  /* Check whether the ARGV-element is a long option.
-
-     If long_only and the ARGV-element has the form "-f", where f is
-     a valid short option, don't consider it an abbreviated form of
-     a long option that starts with f.  Otherwise there would be no
-     way to give the -f short option.
-
-     On the other hand, if there's a long option "fubar" and
-     the ARGV-element is "-fu", do consider that an abbreviation of
-     the long option, just like "--fu", and not "-f" with arg "u".
-
-     This distinction seems to be the most useful approach.  */
-
-  if (longopts != NULL
-      && (argv[optind][1] == '-'
-         || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
-    {
-      char *nameend;
-      const struct option *p;
-      const struct option *pfound = NULL;
-      int exact = 0;
-      int ambig = 0;
-      int indfound = -1;
-      int option_index;
-
-      for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
-       /* Do nothing.  */ ;
-
-      /* Test all long options for either exact match
-        or abbreviated matches.  */
-      for (p = longopts, option_index = 0; p->name; p++, option_index++)
-       if (!strncmp (p->name, nextchar, nameend - nextchar))
-         {
-           if ((unsigned int) (nameend - nextchar)
-               == (unsigned int) strlen (p->name))
-             {
-               /* Exact match found.  */
-               pfound = p;
-               indfound = option_index;
-               exact = 1;
-               break;
-             }
-           else if (pfound == NULL)
-             {
-               /* First nonexact match found.  */
-               pfound = p;
-               indfound = option_index;
-             }
-           else
-             /* Second or later nonexact match found.  */
-             ambig = 1;
-         }
-
-      if (ambig && !exact)
-       {
-         if (opterr)
-           fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
-                    argv[0], argv[optind]);
-         nextchar += strlen (nextchar);
-         optind++;
-         optopt = 0;
-         return '?';
-       }
-
-      if (pfound != NULL)
-       {
-         option_index = indfound;
-         optind++;
-         if (*nameend)
-           {
-             /* Don't test has_arg with >, because some C compilers don't
-                allow it to be used on enums.  */
-             if (pfound->has_arg)
-               optarg = nameend + 1;
-             else
-               {
-                 if (opterr) {
-                  if (argv[optind - 1][1] == '-')
-                   /* --option */
-                   fprintf (stderr,
-                    _("%s: option `--%s' doesn't allow an argument\n"),
-                    argv[0], pfound->name);
-                  else
-                   /* +option or -option */
-                   fprintf (stderr,
-                    _("%s: option `%c%s' doesn't allow an argument\n"),
-                    argv[0], argv[optind - 1][0], pfound->name);
-                 }
-                 nextchar += strlen (nextchar);
-
-                 optopt = pfound->val;
-                 return '?';
-               }
-           }
-         else if (pfound->has_arg == 1)
-           {
-             if (optind < argc)
-               optarg = argv[optind++];
-             else
-               {
-                 if (opterr)
-                   fprintf (stderr,
-                          _("%s: option `%s' requires an argument\n"),
-                          argv[0], argv[optind - 1]);
-                 nextchar += strlen (nextchar);
-                 optopt = pfound->val;
-                 return optstring[0] == ':' ? ':' : '?';
-               }
-           }
-         nextchar += strlen (nextchar);
-         if (longind != NULL)
-           *longind = option_index;
-         if (pfound->flag)
-           {
-             *(pfound->flag) = pfound->val;
-             return 0;
-           }
-         return pfound->val;
-       }
-
-      /* Can't find it as a long option.  If this is not getopt_long_only,
-        or the option starts with '--' or is not a valid short
-        option, then it's an error.
-        Otherwise interpret it as a short option.  */
-      if (!long_only || argv[optind][1] == '-'
-         || my_index (optstring, *nextchar) == NULL)
-       {
-         if (opterr)
-           {
-             if (argv[optind][1] == '-')
-               /* --option */
-               fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
-                        argv[0], nextchar);
-             else
-               /* +option or -option */
-               fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
-                        argv[0], argv[optind][0], nextchar);
-           }
-         nextchar = (char *) "";
-         optind++;
-         optopt = 0;
-         return '?';
-       }
-    }
-
-  /* Look at and handle the next short option-character.  */
-
-  {
-    char c = *nextchar++;
-    char *temp = my_index (optstring, c);
-
-    /* Increment `optind' when we start to process its last character.  */
-    if (*nextchar == '\0')
-      ++optind;
-
-    if (temp == NULL || c == ':')
-      {
-       if (opterr)
-         {
-           if (posixly_correct)
-             /* 1003.2 specifies the format of this message.  */
-             fprintf (stderr, _("%s: illegal option -- %c\n"),
-                      argv[0], c);
-           else
-             fprintf (stderr, _("%s: invalid option -- %c\n"),
-                      argv[0], c);
-         }
-       optopt = c;
-       return '?';
-      }
-    /* Convenience. Treat POSIX -W foo same as long option --foo */
-    if (temp[0] == 'W' && temp[1] == ';')
-      {
-       char *nameend;
-       const struct option *p;
-       const struct option *pfound = NULL;
-       int exact = 0;
-       int ambig = 0;
-       int indfound = 0;
-       int option_index;
-
-       /* This is an option that requires an argument.  */
-       if (*nextchar != '\0')
-         {
-           optarg = nextchar;
-           /* If we end this ARGV-element by taking the rest as an arg,
-              we must advance to the next element now.  */
-           optind++;
-         }
-       else if (optind == argc)
-         {
-           if (opterr)
-             {
-               /* 1003.2 specifies the format of this message.  */
-               fprintf (stderr, _("%s: option requires an argument -- %c\n"),
-                        argv[0], c);
-             }
-           optopt = c;
-           if (optstring[0] == ':')
-             c = ':';
-           else
-             c = '?';
-           return c;
-         }
-       else
-         /* We already incremented `optind' once;
-            increment it again when taking next ARGV-elt as argument.  */
-         optarg = argv[optind++];
-
-       /* optarg is now the argument, see if it's in the
-          table of longopts.  */
-
-       for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
-         /* Do nothing.  */ ;
-
-       /* Test all long options for either exact match
-          or abbreviated matches.  */
-       for (p = longopts, option_index = 0; p->name; p++, option_index++)
-         if (!strncmp (p->name, nextchar, nameend - nextchar))
-           {
-             if ((unsigned int) (nameend - nextchar) == strlen (p->name))
-               {
-                 /* Exact match found.  */
-                 pfound = p;
-                 indfound = option_index;
-                 exact = 1;
-                 break;
-               }
-             else if (pfound == NULL)
-               {
-                 /* First nonexact match found.  */
-                 pfound = p;
-                 indfound = option_index;
-               }
-             else
-               /* Second or later nonexact match found.  */
-               ambig = 1;
-           }
-       if (ambig && !exact)
-         {
-           if (opterr)
-             fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
-                      argv[0], argv[optind]);
-           nextchar += strlen (nextchar);
-           optind++;
-           return '?';
-         }
-       if (pfound != NULL)
-         {
-           option_index = indfound;
-           if (*nameend)
-             {
-               /* Don't test has_arg with >, because some C compilers don't
-                  allow it to be used on enums.  */
-               if (pfound->has_arg)
-                 optarg = nameend + 1;
-               else
-                 {
-                   if (opterr)
-                     fprintf (stderr, _("\
-%s: option `-W %s' doesn't allow an argument\n"),
-                              argv[0], pfound->name);
-
-                   nextchar += strlen (nextchar);
-                   return '?';
-                 }
-             }
-           else if (pfound->has_arg == 1)
-             {
-               if (optind < argc)
-                 optarg = argv[optind++];
-               else
-                 {
-                   if (opterr)
-                     fprintf (stderr,
-                              _("%s: option `%s' requires an argument\n"),
-                              argv[0], argv[optind - 1]);
-                   nextchar += strlen (nextchar);
-                   return optstring[0] == ':' ? ':' : '?';
-                 }
-             }
-           nextchar += strlen (nextchar);
-           if (longind != NULL)
-             *longind = option_index;
-           if (pfound->flag)
-             {
-               *(pfound->flag) = pfound->val;
-               return 0;
-             }
-           return pfound->val;
-         }
-         nextchar = NULL;
-         return 'W';   /* Let the application handle it.   */
-      }
-    if (temp[1] == ':')
-      {
-       if (temp[2] == ':')
-         {
-           /* This is an option that accepts an argument optionally.  */
-           if (*nextchar != '\0')
-             {
-               optarg = nextchar;
-               optind++;
-             }
-           else
-             optarg = NULL;
-           nextchar = NULL;
-         }
-       else
-         {
-           /* This is an option that requires an argument.  */
-           if (*nextchar != '\0')
-             {
-               optarg = nextchar;
-               /* If we end this ARGV-element by taking the rest as an arg,
-                  we must advance to the next element now.  */
-               optind++;
-             }
-           else if (optind == argc)
-             {
-               if (opterr)
-                 {
-                   /* 1003.2 specifies the format of this message.  */
-                   fprintf (stderr,
-                          _("%s: option requires an argument -- %c\n"),
-                          argv[0], c);
-                 }
-               optopt = c;
-               if (optstring[0] == ':')
-                 c = ':';
-               else
-                 c = '?';
-             }
-           else
-             /* We already incremented `optind' once;
-                increment it again when taking next ARGV-elt as argument.  */
-             optarg = argv[optind++];
-           nextchar = NULL;
-         }
-      }
-    return c;
-  }
-}
-
-int
-getopt (argc, argv, optstring)
-     int argc;
-     char *const *argv;
-     const char *optstring;
-{
-  return _getopt_internal (argc, argv, optstring,
-                          (const struct option *) 0,
-                          (int *) 0,
-                          0);
-}
-
-#endif /* Not ELIDE_CODE.  */
-\f
-#ifdef TEST
-
-/* Compile with -DTEST to make an executable for use in testing
-   the above definition of `getopt'.  */
-
-int
-main (argc, argv)
-     int argc;
-     char **argv;
-{
-  int c;
-  int digit_optind = 0;
-
-  while (1)
-    {
-      int this_option_optind = optind ? optind : 1;
-
-      c = getopt (argc, argv, "abc:d:0123456789");
-      if (c == -1)
-       break;
-
-      switch (c)
-       {
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-         if (digit_optind != 0 && digit_optind != this_option_optind)
-           printf ("digits occur in two different argv-elements.\n");
-         digit_optind = this_option_optind;
-         printf ("option %c\n", c);
-         break;
-
-       case 'a':
-         printf ("option a\n");
-         break;
-
-       case 'b':
-         printf ("option b\n");
-         break;
-
-       case 'c':
-         printf ("option c with value `%s'\n", optarg);
-         break;
-
-       case '?':
-         break;
-
-       default:
-         printf ("?? getopt returned character code 0%o ??\n", c);
-       }
-    }
-
-  if (optind < argc)
-    {
-      printf ("non-option ARGV-elements: ");
-      while (optind < argc)
-       printf ("%s ", argv[optind++]);
-      printf ("\n");
-    }
-
-  exit (0);
-}
-
-#endif /* TEST */
diff --git a/src/getopt.h b/src/getopt.h
deleted file mode 100644 (file)
index 7dad11b..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/* Declarations for getopt.
-   Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
-
-   This file is part of the GNU C Library.  Its master source is NOT part of
-   the C library, however.  The master source lives in /gd/gnu/lib.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-
-#ifndef _GETOPT_H
-#define _GETOPT_H 1
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* For communication from `getopt' to the caller.
-   When `getopt' finds an option that takes an argument,
-   the argument value is returned here.
-   Also, when `ordering' is RETURN_IN_ORDER,
-   each non-option ARGV-element is returned here.  */
-
-extern char *optarg;
-
-/* Index in ARGV of the next element to be scanned.
-   This is used for communication to and from the caller
-   and for communication between successive calls to `getopt'.
-
-   On entry to `getopt', zero means this is the first call; initialize.
-
-   When `getopt' returns -1, this is the index of the first of the
-   non-option elements that the caller should itself scan.
-
-   Otherwise, `optind' communicates from one call to the next
-   how much of ARGV has been scanned so far.  */
-
-extern int optind;
-
-/* Callers store zero here to inhibit the error message `getopt' prints
-   for unrecognized options.  */
-
-extern int opterr;
-
-/* Set to an option character which was unrecognized.  */
-
-extern int optopt;
-
-/* Describe the long-named options requested by the application.
-   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
-   of `struct option' terminated by an element containing a name which is
-   zero.
-
-   The field `has_arg' is:
-   no_argument         (or 0) if the option does not take an argument,
-   required_argument   (or 1) if the option requires an argument,
-   optional_argument   (or 2) if the option takes an optional argument.
-
-   If the field `flag' is not NULL, it points to a variable that is set
-   to the value given in the field `val' when the option is found, but
-   left unchanged if the option is not found.
-
-   To have a long-named option do something other than set an `int' to
-   a compiled-in constant, such as set a value from `optarg', set the
-   option's `flag' field to zero and its `val' field to a nonzero
-   value (the equivalent single-letter option character, if there is
-   one).  For long options that have a zero `flag' field, `getopt'
-   returns the contents of the `val' field.  */
-
-struct option
-{
-#if defined (__STDC__) && __STDC__
-  const char *name;
-#else
-  char *name;
-#endif
-  /* has_arg can't be an enum because some compilers complain about
-     type mismatches in all the code that assumes it is an int.  */
-  int has_arg;
-  int *flag;
-  int val;
-};
-
-/* Names for the values of the `has_arg' field of `struct option'.  */
-
-#define        no_argument             0
-#define required_argument      1
-#define optional_argument      2
-
-#if defined (__STDC__) && __STDC__
-#ifdef __GNU_LIBRARY__
-/* Many other libraries have conflicting prototypes for getopt, with
-   differences in the consts, in stdlib.h.  To avoid compilation
-   errors, only prototype getopt for the GNU C library.  */
-extern int getopt (int argc, char *const *argv, const char *shortopts);
-#else /* not __GNU_LIBRARY__ */
-extern int getopt ();
-#endif /* __GNU_LIBRARY__ */
-extern int getopt_long (int argc, char *const *argv, const char *shortopts,
-                       const struct option *longopts, int *longind);
-extern int getopt_long_only (int argc, char *const *argv,
-                            const char *shortopts,
-                            const struct option *longopts, int *longind);
-
-/* Internal only.  Users should not call this directly.  */
-extern int _getopt_internal (int argc, char *const *argv,
-                            const char *shortopts,
-                            const struct option *longopts, int *longind,
-                            int long_only);
-#else /* not __STDC__ */
-extern int getopt ();
-extern int getopt_long ();
-extern int getopt_long_only ();
-
-extern int _getopt_internal ();
-#endif /* __STDC__ */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _GETOPT_H */
diff --git a/src/getopt1.c b/src/getopt1.c
deleted file mode 100644 (file)
index 8347bb1..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-/* getopt_long and getopt_long_only entry points for GNU getopt.
-   Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc.
-
-   This file is part of the GNU C Library.  Its master source is NOT part of
-   the C library, however.  The master source lives in /gd/gnu/lib.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-\f
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "getopt.h"
-
-#if !defined (__STDC__) || !__STDC__
-/* This is a separate conditional since some stdc systems
-   reject `defined (const)'.  */
-#ifndef const
-#define const
-#endif
-#endif
-
-#include <stdio.h>
-
-/* Comment out all this code if we are using the GNU C Library, and are not
-   actually compiling the library itself.  This code is part of the GNU C
-   Library, but also included in many other GNU distributions.  Compiling
-   and linking in this code is a waste when using the GNU C library
-   (especially if it is a shared library).  Rather than having every GNU
-   program understand `configure --with-gnu-libc' and omit the object files,
-   it is simpler to just do this in the source for each such file.  */
-
-#define GETOPT_INTERFACE_VERSION 2
-#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
-#include <gnu-versions.h>
-#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
-#define ELIDE_CODE
-#endif
-#endif
-
-#ifndef ELIDE_CODE
-
-
-/* This needs to come after some library #include
-   to get __GNU_LIBRARY__ defined.  */
-#ifdef __GNU_LIBRARY__
-#include <stdlib.h>
-#endif
-
-#ifndef        NULL
-#define NULL 0
-#endif
-
-int
-getopt_long (argc, argv, options, long_options, opt_index)
-     int argc;
-     char *const *argv;
-     const char *options;
-     const struct option *long_options;
-     int *opt_index;
-{
-  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
-}
-
-/* Like getopt_long, but '-' as well as '--' can indicate a long option.
-   If an option that starts with '-' (not '--') doesn't match a long option,
-   but does match a short option, it is parsed as a short option
-   instead.  */
-
-int
-getopt_long_only (argc, argv, options, long_options, opt_index)
-     int argc;
-     char *const *argv;
-     const char *options;
-     const struct option *long_options;
-     int *opt_index;
-{
-  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
-}
-
-
-#endif /* Not ELIDE_CODE.  */
-\f
-#ifdef TEST
-
-#include <stdio.h>
-
-int
-main (argc, argv)
-     int argc;
-     char **argv;
-{
-  int c;
-  int digit_optind = 0;
-
-  while (1)
-    {
-      int this_option_optind = optind ? optind : 1;
-      int option_index = 0;
-      static struct option long_options[] =
-      {
-       {"add", 1, 0, 0},
-       {"append", 0, 0, 0},
-       {"delete", 1, 0, 0},
-       {"verbose", 0, 0, 0},
-       {"create", 0, 0, 0},
-       {"file", 1, 0, 0},
-       {0, 0, 0, 0}
-      };
-
-      c = getopt_long (argc, argv, "abc:d:0123456789",
-                      long_options, &option_index);
-      if (c == -1)
-       break;
-
-      switch (c)
-       {
-       case 0:
-         printf ("option %s", long_options[option_index].name);
-         if (optarg)
-           printf (" with arg %s", optarg);
-         printf ("\n");
-         break;
-
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-         if (digit_optind != 0 && digit_optind != this_option_optind)
-           printf ("digits occur in two different argv-elements.\n");
-         digit_optind = this_option_optind;
-         printf ("option %c\n", c);
-         break;
-
-       case 'a':
-         printf ("option a\n");
-         break;
-
-       case 'b':
-         printf ("option b\n");
-         break;
-
-       case 'c':
-         printf ("option c with value `%s'\n", optarg);
-         break;
-
-       case 'd':
-         printf ("option d with value `%s'\n", optarg);
-         break;
-
-       case '?':
-         break;
-
-       default:
-         printf ("?? getopt returned character code 0%o ??\n", c);
-       }
-    }
-
-  if (optind < argc)
-    {
-      printf ("non-option ARGV-elements: ");
-      while (optind < argc)
-       printf ("%s ", argv[optind++]);
-      printf ("\n");
-    }
-
-  exit (0);
-}
-
-#endif /* TEST */
diff --git a/src/gifsize.c b/src/gifsize.c
deleted file mode 100644 (file)
index 074755d..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-/****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
- ****************************************************************************
- * gifsize.c  provides the function gifsize which determines the size of a gif
- ****************************************************************************/
-
-/* This is built from code originally created by:                        */
-
-/* +-------------------------------------------------------------------+ */
-/* | Copyright 1990, 1991, 1993, David Koblas.  (koblas@netcom.com)    | */
-/* |   Permission to use, copy, modify, and distribute this software   | */
-/* |   and its documentation for any purpose and without fee is hereby | */
-/* |   granted, provided that the above copyright notice appear in all | */
-/* |   copies and that both that copyright notice and this permission  | */
-/* |   notice appear in supporting documentation.  This software is    | */
-/* |   provided "as is" without express or implied warranty.           | */
-/* +-------------------------------------------------------------------+ */
-
-
-#include <stdio.h>
-#include <math.h>
-#include <string.h>
-#include <stdlib.h>
-
-
-#define MAXCOLORMAPSIZE     256
-
-#define TRUE                1
-#define FALSE               0
-
-#define CM_RED              0
-#define CM_GREEN            1
-#define CM_BLUE             2
-
-
-#define LOCALCOLORMAP       0x80
-#define BitSet(byte, bit)   (((byte) & (bit)) == (bit))
-
-#define ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
-
-#define LM_to_uint(a,b)     (((b)<<8)|(a))
-
-
-static struct {
-       int     transparent;
-       int     delayTime;
-       int     inputFlag;
-       int     disposal;
-} Gif89 = { -1, -1, -1, 0 };
-
-static int ReadColorMap (FILE *fd, int number, unsigned char (*buffer)[256]);
-static int DoExtension (FILE *fd, int label, int *Transparent);
-static int GetDataBlock (FILE *fd, unsigned char *buf);
-
-int ZeroDataBlock;
-
-int
-GifSize(FILE *fd, long *width, long *height)
-{
-       int imageNumber;
-       int BitPixel;
-       int ColorResolution;
-       int Background;
-       int AspectRatio;
-       int Transparent = (-1);
-       unsigned char   buf[16];
-       unsigned char   c;
-       unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
-       int             imageCount = 0;
-       char            version[4];
-       ZeroDataBlock = FALSE;
-
-       imageNumber = 1;
-       if (! ReadOK(fd,buf,6)) {
-               return 0;
-       }
-       if (strncmp((char *)buf,"GIF",3) != 0) {
-               return 0;
-       }
-       strncpy(version, (char *)buf + 3, 3);
-       version[3] = '\0';
-
-       if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
-               return 0;
-       }
-       if (! ReadOK(fd,buf,7)) {
-               return 0;
-       }
-       BitPixel        = 2<<(buf[4]&0x07);
-       ColorResolution = (int) (((buf[4]&0x70)>>3)+1);
-       Background      = buf[5];
-       AspectRatio     = buf[6];
-
-       if (BitSet(buf[4], LOCALCOLORMAP)) {    /* Global Colormap */
-               if (ReadColorMap(fd, BitPixel, ColorMap)) {
-                       return 0;
-               }
-       }
-       for (;;) {
-               if (! ReadOK(fd,&c,1)) {
-                       return 0;
-               }
-               if (c == ';') {         /* GIF terminator */
-                       if (imageCount < imageNumber) {
-                               return 0;
-                       }
-               }
-
-               if (c == '!') {         /* Extension */
-                       if (! ReadOK(fd,&c,1)) {
-                               return 0;
-                       }
-                       DoExtension(fd, c, &Transparent);
-                       continue;
-               }
-
-               if (c != ',') {         /* Not a valid start character */
-                       continue;
-               }
-
-               ++imageCount;
-
-               if (! ReadOK(fd,buf,9)) {
-                      return 0;
-               }
-
-               (*width) = LM_to_uint(buf[4],buf[5]);
-               (*height) = LM_to_uint(buf[6],buf[7]);
-              return 1;
-       }
-}
-
-static int
-ReadColorMap(FILE *fd, int number, unsigned char (*buffer)[256])
-{
-       int             i;
-       unsigned char   rgb[3];
-
-
-       for (i = 0; i < number; ++i) {
-               if (! ReadOK(fd, rgb, sizeof(rgb))) {
-                       return TRUE;
-               }
-               buffer[CM_RED][i] = rgb[0] ;
-               buffer[CM_GREEN][i] = rgb[1] ;
-               buffer[CM_BLUE][i] = rgb[2] ;
-       }
-
-
-       return FALSE;
-}
-
-static int
-DoExtension(FILE *fd, int label, int *Transparent)
-{
-       static unsigned char     buf[256];
-
-       switch (label) {
-       case 0xf9:              /* Graphic Control Extension */
-               (void) GetDataBlock(fd, (unsigned char*) buf);
-               Gif89.disposal    = (buf[0] >> 2) & 0x7;
-               Gif89.inputFlag   = (buf[0] >> 1) & 0x1;
-               Gif89.delayTime   = LM_to_uint(buf[1],buf[2]);
-               if ((buf[0] & 0x1) != 0)
-                       *Transparent = buf[3];
-
-               while (GetDataBlock(fd, (unsigned char*) buf) != 0)
-                       ;
-               return FALSE;
-       default:
-               break;
-       }
-       while (GetDataBlock(fd, (unsigned char*) buf) != 0)
-               ;
-
-       return FALSE;
-}
-
-static int
-GetDataBlock(FILE *fd, unsigned char *buf)
-{
-       unsigned char   count;
-
-       if (! ReadOK(fd,&count,1)) {
-               return -1;
-       }
-
-       ZeroDataBlock = count == 0;
-
-       if ((count != 0) && (! ReadOK(fd, buf, count))) {
-               return -1;
-       }
-
-       return count;
-}
-
index 3fda164c2d3cfd951168d56c5c5524adda20eb7d..d7edbee753327a079846b8199eb8deede5195a5e 100644 (file)
  *      argument on the first call to either fnv_32_buf() or fnv_32_str().
  */
 Fnv32_t
-fnv_32_buf(void *buf, size_t len, Fnv32_t hval)
+fnv_32_buf(const void *buf, size_t len, Fnv32_t hval)
 {
-    unsigned char *bp = (unsigned char *)buf;  /* start of buffer */
-    unsigned char *be = bp + len;              /* beyond end of buffer */
+    const unsigned char *bp = (const unsigned char *)buf;      /* start of buffer */
+    const unsigned char *be = bp + len;                /* beyond end of buffer */
 
     /*
      * FNV-1 hash each octet in the buffer
@@ -125,9 +125,9 @@ fnv_32_buf(void *buf, size_t len, Fnv32_t hval)
  *      argument on the first call to either fnv_32_buf() or fnv_32_str().
  */
 Fnv32_t
-fnv_32_str(char *str, Fnv32_t hval)
+fnv_32_str(const char *str, Fnv32_t hval)
 {
-    unsigned char *s = (unsigned char *)str;   /* unsigned string */
+    const unsigned char *s = (const unsigned char *)str;       /* unsigned string */
 
     /*
      * FNV-1 hash each octet in the buffer
@@ -146,7 +146,7 @@ fnv_32_str(char *str, Fnv32_t hval)
 }
 
 /* a wrapper function for fnv_32_str */
-unsigned long FnvHash(char *str)
+unsigned long FnvHash(const char *str)
 {
   return fnv_32_str(str,FNV1_32_INIT);
 }
index 775a40a2552776ad92c660529612f14944e9f302..919dd50b340d74ed8806c59af2e9ae88b0082aaf 100644 (file)
@@ -659,7 +659,8 @@ assign_date(struct rrd_time_value *ptv, long mday, long mon, long year)
 static char *
 day(struct rrd_time_value *ptv)
 {
-    long mday=0, wday, mon, year = ptv->tm.tm_year;
+    /* using time_t seems to help portability with 64bit oses */    
+    time_t mday=0, wday, mon, year = ptv->tm.tm_year;
     int tlen;
 
     switch (sc_tokid) {
@@ -836,8 +837,23 @@ parsetime(const char *tspec, struct rrd_time_value *ptv)
 
     /* Only absolute time specifications below */
     case NUMBER:
-           try(tod(ptv))
-            try(day(ptv))
+           {
+             long hour_sv = ptv->tm.tm_hour;
+             long year_sv = ptv->tm.tm_year;
+              ptv->tm.tm_hour = 30;
+              ptv->tm.tm_year = 30000;
+             try(tod(ptv))
+             try(day(ptv))
+             if ( ptv->tm.tm_hour == 30 &&  ptv->tm.tm_year != 30000 ){
+               try(tod(ptv))
+              }
+             if ( ptv->tm.tm_hour == 30 ){
+               ptv->tm.tm_hour = hour_sv;
+              }
+             if ( ptv->tm.tm_year == 30000 ){
+               ptv->tm.tm_year = year_sv;
+              }
+           };      
             break;
     /* fix month parsing */
     case JAN: case FEB: case MAR: case APR: case MAY: case JUN:
index e60b6fab0f9f8075b86d02cb2cb04b173e7473c8..78d0950863db60152da1561fa2e4ee43fea3f4dc 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * pngsize.c  determine the size of a PNG image
  *****************************************************************************/
@@ -22,6 +22,13 @@ PngSize(FILE *fd, long *width, long *height)
   (*width)=0;
   (*height)=0;
 
+/* this is to make compile on aix work since they seem to define jmpbuf
+   to be _jmpbuf which breaks compilation */
+
+#ifdef jmpbuf
+#undef jmpbuf
+#endif
+
   if (setjmp(png_read_ptr->jmpbuf)){
     png_destroy_read_struct(&png_read_ptr, &info_ptr, (png_infopp)NULL);
     return 0;
diff --git a/src/rrd.dsp b/src/rrd.dsp
deleted file mode 100644 (file)
index 61e102c..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-# Microsoft Developer Studio Project File - Name="rrd" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Static Library" 0x0104
-
-CFG=rrd - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE 
-!MESSAGE NMAKE /f "rrd.mak".
-!MESSAGE 
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE 
-!MESSAGE NMAKE /f "rrd.mak" CFG="rrd - Win32 Debug"
-!MESSAGE 
-!MESSAGE Possible choices for configuration are:
-!MESSAGE 
-!MESSAGE "rrd - Win32 Release" (based on "Win32 (x86) Static Library")
-!MESSAGE "rrd - Win32 Debug" (based on "Win32 (x86) Static Library")
-!MESSAGE 
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF  "$(CFG)" == "rrd - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "rrd___Wi"
-# PROP BASE Intermediate_Dir "rrd___Wi"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "release"
-# PROP Intermediate_Dir "release"
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
-# ADD CPP /nologo /MD /W3 /GX /I "\Program Files\GnuWin32\include" /I "\Program Files\GnuWin32\include\freetype2" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_CTYPE_DISABLE_MACROS" /FD /c
-# SUBTRACT CPP /X /YX
-# ADD BASE RSC /l 0x100c
-# ADD RSC /l 0x100c
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LIB32=link.exe -lib
-# ADD BASE LIB32 /nologo
-# ADD LIB32 /nologo
-
-!ELSEIF  "$(CFG)" == "rrd - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "rrd___W0"
-# PROP BASE Intermediate_Dir "rrd___W0"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "debug"
-# PROP Intermediate_Dir "debug"
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
-# ADD CPP /nologo /MD /W3 /Gm /GX /ZI /Od /I "\Program Files\GnuWin32\include\freetype2" /I "\Program Files\GnuWin32\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "_CTYPE_DISABLE_MACROS" /FR /FD /c
-# SUBTRACT CPP /X /YX
-# ADD BASE RSC /l 0x100c
-# ADD RSC /l 0x100c
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo /o"rrd.bsc"
-LIB32=link.exe -lib
-# ADD BASE LIB32 /nologo
-# ADD LIB32 /nologo
-
-!ENDIF 
-
-# Begin Target
-
-# Name "rrd - Win32 Release"
-# Name "rrd - Win32 Debug"
-# Begin Source File
-
-SOURCE=.\getopt.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\getopt1.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\hash_32.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\parsetime.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\pngsize.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_afm.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_afm_data.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_create.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_diff.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_dump.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_error.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_fetch.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_format.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_gfx.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_graph.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_graph_helper.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_hw.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_info.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_last.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_nan_inf.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_open.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_resize.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_restore.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_rpncalc.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_thread_safe_nt.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_tune.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_update.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rrd_xport.c
-# End Source File
-# End Target
-# End Project
index 49164e381fdd9e9baeb1d13fabb8f664778e2326..3873033e7696c6146a0a9d00a72aff586339c4b2 100644 (file)
--- a/src/rrd.h
+++ b/src/rrd.h
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.0.33  Copyright Tobias Oetiker, 1997,1998, 1999
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrdlib.h   Public header file for librrd
  *****************************************************************************
@@ -72,19 +72,28 @@ int    rrd_tune(int, char **);
 time_t rrd_last(int, char **);
 time_t rrd_first(int, char **);
 int    rrd_resize(int, char **);
+char * rrd_strversion(void);
+double rrd_version(void);
 int    rrd_xport(int, char **, int *, time_t *, time_t *,
                 unsigned long *, unsigned long *,
                 char ***, rrd_value_t **);
 
 /* thread-safe (hopefully) */
-int    rrd_create_r(char *filename,
+int    rrd_create_r(const char *filename,
                    unsigned long pdp_step, time_t last_up,
-                   int argc, char **argv);
+                   int argc, const char **argv);
 /* NOTE: rrd_update_r are only thread-safe if no at-style time
    specifications get used!!! */
-int    rrd_update_r(char *filename, char *_template,
-                   int argc, char **argv);
-int    rrd_dump_r(char *filename);
+
+int    rrd_update_r(const char *filename, const char *_template,
+                   int argc, const char **argv);
+int    rrd_fetch_r(const char *filename, const char* cf,
+                   time_t *start, time_t *end,
+                   unsigned long *step,
+                   unsigned long *ds_cnt,
+                   char        ***ds_namv,
+                   rrd_value_t **data);
+int    rrd_dump_r(const char *filename, char *outname);
 time_t rrd_last_r(const char *filename);
 time_t rrd_first_r(const char *filename, int rraindex);
 
@@ -103,6 +112,9 @@ struct rrd_time_value {
   struct tm tm;
 };
 
+char *parsetime(const char *spec, struct rrd_time_value *ptv);
+/* END parsetime.h */
+
 struct rrd_context {
     int len;
     int errlen;
@@ -113,8 +125,6 @@ struct rrd_context {
 /* returns the current per-thread rrd_context */
 struct rrd_context *rrd_get_context(void);
 
-char *parsetime(const char *spec, struct rrd_time_value *ptv);
-/* END parsetime.h */
 
 int proc_start_end (struct rrd_time_value *,  struct rrd_time_value *, time_t *, time_t *);
 
diff --git a/src/rrd.vcproj b/src/rrd.vcproj
deleted file mode 100644 (file)
index 07df437..0000000
+++ /dev/null
@@ -1,648 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
-       ProjectType="Visual C++"
-       Version="7.10"
-       Name="rrd"
-       SccProjectName=""
-       SccLocalPath="">
-       <Platforms>
-               <Platform
-                       Name="Win32"/>
-       </Platforms>
-       <Configurations>
-               <Configuration
-                       Name="Release|Win32"
-                       OutputDirectory=".\release"
-                       IntermediateDirectory=".\release"
-                       ConfigurationType="4"
-                       UseOfMFC="0"
-                       ATLMinimizesCRunTimeLibraryUsage="FALSE"
-                       CharacterSet="2">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="4"
-                               AdditionalIncludeDirectories="\Program Files\GnuWin32\include,\Program Files\GnuWin32\include\freetype2"
-                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_CTYPE_DISABLE_MACROS"
-                               RuntimeLibrary="2"
-                               PrecompiledHeaderFile=".\release/rrd.pch"
-                               AssemblerListingLocation=".\release/"
-                               ObjectFile=".\release/"
-                               ProgramDataBaseFileName=".\release/"
-                               WarningLevel="3"
-                               SuppressStartupBanner="TRUE"
-                               CompileAs="0"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLibrarianTool"
-                               OutputFile=".\release\rrd.lib"
-                               SuppressStartupBanner="TRUE"/>
-                       <Tool
-                               Name="VCMIDLTool"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"
-                               Culture="4108"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCXMLDataGeneratorTool"/>
-                       <Tool
-                               Name="VCManagedWrapperGeneratorTool"/>
-                       <Tool
-                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
-               </Configuration>
-               <Configuration
-                       Name="Debug|Win32"
-                       OutputDirectory=".\debug"
-                       IntermediateDirectory=".\debug"
-                       ConfigurationType="4"
-                       UseOfMFC="0"
-                       ATLMinimizesCRunTimeLibraryUsage="FALSE"
-                       CharacterSet="2">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="0"
-                               AdditionalIncludeDirectories="\Program Files\GnuWin32\include\freetype2,\Program Files\GnuWin32\include"
-                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CTYPE_DISABLE_MACROS"
-                               RuntimeLibrary="2"
-                               PrecompiledHeaderFile=".\debug/rrd.pch"
-                               AssemblerListingLocation=".\debug/"
-                               ObjectFile=".\debug/"
-                               ProgramDataBaseFileName=".\debug/"
-                               BrowseInformation="1"
-                               WarningLevel="3"
-                               SuppressStartupBanner="TRUE"
-                               DebugInformationFormat="4"
-                               CompileAs="0"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLibrarianTool"
-                               OutputFile=".\debug\rrd.lib"
-                               SuppressStartupBanner="TRUE"/>
-                       <Tool
-                               Name="VCMIDLTool"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"
-                               Culture="4108"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCXMLDataGeneratorTool"/>
-                       <Tool
-                               Name="VCManagedWrapperGeneratorTool"/>
-                       <Tool
-                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
-               </Configuration>
-       </Configurations>
-       <References>
-       </References>
-       <Files>
-               <File
-                       RelativePath="getopt.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="getopt1.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="hash_32.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="parsetime.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="pngsize.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_afm.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_afm_data.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_create.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_diff.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_dump.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_error.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_fetch.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_format.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_gfx.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_graph.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_graph_helper.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_hw.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_info.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_last.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_nan_inf.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_open.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_resize.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_restore.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_rpncalc.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_thread_safe_nt.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_tune.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_update.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-               <File
-                       RelativePath="rrd_xport.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-       </Files>
-       <Globals>
-       </Globals>
-</VisualStudioProject>
index 47e4c77829640ad01387481635202a3d5279ae96..c42e6fecbdd0f24752a2f52cfd8040fe5aece867 100644 (file)
@@ -1,25 +1,30 @@
 /****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  ****************************************************************************
  * rrd_afm.h  Parsing afm tables to find width of strings.
- ****************************************************************************/
+ ****************************************************************************
+ * $Id$
+*/
 
-#ifdef WIN32
-#include "../confignt/config.h"
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__) && !defined(HAVE_CONFIG_H)
+#include "../win32/config.h"
 #else
-#include "config.h"
+#ifdef HAVE_CONFIG_H
+#include "../rrd_config.h"
+#endif
 #endif
 
 #include "rrd_afm.h"
 #include "rrd_afm_data.h"
 
-#include <stdlib.h>
 #include <stdio.h>
 
 #ifdef HAVE_STRING_H
 #include <string.h>
 #endif
 
+#include "unused.h"
+
 #if 0
 # define DEBUG 1
 # define DLOG(x) fprintf x
@@ -34,7 +39,8 @@
 */
 #define ENABLE_LIGATURES 0
 
-static const afm_fontinfo *afm_last_used_font;
+static const afm_fontinfo *afm_last_used_font = NULL;
+static const char *last_unknown_font = NULL;
 
 #define is_font(p, name) \
   (!strcmp(p->postscript_name, name) || !strcmp(p->fullname, name))
@@ -55,22 +61,47 @@ static const afm_fontinfo *afm_searchfont(const char *name)
   return NULL;
 }
 
+
+/* returns always a font, never NULL.
+   The rest of the code depends on the result never being NULL.
+   See rrd_afm.h */
 static const afm_fontinfo *afm_findfont(const char *name)
 {
   const afm_fontinfo *p = afm_searchfont(name);
   if (p)
     return p;
-  if (1 || DEBUG) fprintf(stderr, "Can't find font '%s'\n", name);
-  p = afm_searchfont("Helvetica");
+  if (!last_unknown_font || strcmp(name, last_unknown_font)) {
+         fprintf(stderr, "Can't find font '%s'\n", name);
+         last_unknown_font = name;
+  }
+  p = afm_searchfont(RRD_AFM_DEFAULT_FONT);
   if (p)
     return p;
-  return NULL;
+  return afm_fontinfolist; /* anything, just anything. */
 }
 
 const char *afm_get_font_postscript_name(const char* font)
 {
   const afm_fontinfo *p = afm_findfont(font);
-  return p ? p->postscript_name : "Helvetica";
+  return p->postscript_name;
+}
+
+const char *afm_get_font_name(const char* font)
+{
+  const afm_fontinfo *p = afm_findfont(font);
+  return p->fullname;
+}
+
+double afm_get_ascender(const char* font, double size)
+{
+  const afm_fontinfo *p = afm_findfont(font);
+  return size * p->ascender / 1000.0;
+}
+
+double afm_get_descender(const char* font, double size)
+{
+  const afm_fontinfo *p = afm_findfont(font);
+  return size * p->descender / 1000.0;
 }
 
 static int afm_find_char_index(const afm_fontinfo *fontinfo,
@@ -159,24 +190,49 @@ static long afm_find_kern(const afm_fontinfo *fontinfo,
 }
 
 /* measure width of a text string */
-double afm_get_text_width ( double start, const char* font, double size,
+double afm_get_text_width( double start, const char* font, double size,
           double tabwidth, const char* text)
+{
+#ifdef HAVE_MBSTOWCS     
+    size_t clen = strlen(text) + 1;
+    wchar_t *cstr = malloc(sizeof(wchar_t) * clen); /* yes we are allocating probably too much here, I know */
+    int text_count = mbstowcs(cstr, text, clen);
+    double w;
+    if (text_count == -1)
+           text_count = mbstowcs(cstr, "Enc-Err", 6);
+#ifdef __APPLE__
+       while (text_count > 0) {
+               text_count--;
+               cstr[text_count] = afm_fix_osx_charset(cstr[text_count]); /* unsafe macro */
+       }
+#endif
+    w = afm_get_text_width_wide(start, font, size, tabwidth, cstr);
+    free(cstr);
+    return w;
+#else
+    return afm_get_text_width_wide(start, font, size, tabwidth, text);
+#endif
+}
+
+double afm_get_text_width_wide( double UNUSED(start), const char* font, double size,
+          double UNUSED(tabwidth), const afm_char* text)
 {
   const afm_fontinfo *fontinfo = afm_findfont(font);
   long width = 0;
   double widthf;
-  const unsigned char *up = (const unsigned char*)text;
+  const afm_char *up = text;
   DLOG((stderr, "================= %s\n", text));
-  if (fontinfo == NULL)
-    return size * strlen(text);
+  if (fontinfo == NULL) {
+      while (*up)
+         up++;
+    return size * (up - text);
+  }
   while (1) {
     afm_unicode ch1, ch2;
     int idx1, kern_idx;
     if ((ch1 = *up) == 0)
-      break;
-    ch1 = afm_host2unicode(ch1); /* unsafe macro */
+        break;
     ch2 = *++up;
-    ch2 = afm_host2unicode(ch2); /* unsafe macro */
     DLOG((stderr, "------------- Loop: %d + %d (%c%c)   at %d\n",
           ch1, ch2, ch1, ch2 ? ch2 : ' ',
          (up - (const unsigned char*)text) - 1));
@@ -189,7 +245,7 @@ double afm_get_text_width ( double start, const char* font, double size,
       if (ch1_new) {
         ch1 = ch1_new;
         idx1 = afm_find_char_index(fontinfo, ch1);
-        ch2 = afm_host2unicode(*++up);
+        ch2 = *++up;
         DLOG((stderr, "  -> idx1 = %d, ch2 = %d (%c)\n", 
             idx1, ch2, ch2 ? ch2 : ' '));
       }
index ec82989c858db886a98998491da51f4f73ea9602..20350ff2c03c13acf9a7d1d3c73b3873e3ff85e0 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  ****************************************************************************
  * rrd_afm.h  Parsing afm tables to find width of strings.
  ****************************************************************************/
@@ -7,23 +7,48 @@
 #ifndef  RRD_AFM_H
 #define RRD_AFM_H
 
+#include <stdlib.h>
+#ifdef HAVE_MBSTOWCS
+#define afm_char wchar_t
+#else
+#define afm_char unsigned char
+#endif
+/*
+   If the font specified by the name parameter in the routes below
+   is not found
+   (because it is not compiled into rrd_afm_data.c by compile_afm.pl)
+   the font specified by RRD_AFM_DEFAULT_FONT will be used.
+   If it is not installed, it uses the first font compiled
+   into rrd_afm_data.c
+   So they will always use some font.
+*/
+
+#define RRD_AFM_DEFAULT_FONT "Courier"
+
 /* measure width of a text string */
 /* fontname can be full name or postscript name */
-double afm_get_text_width ( double start, const char* font, double size,
+double afm_get_text_width( double start, const char* font, double size,
                            double tabwidth, const char* text);
+double afm_get_text_width_wide( double start, const char* font, double size,
+                           double tabwidth, const afm_char* text);
+
+double afm_get_ascender(const char* font, double size);
+double afm_get_descender(const char* font, double size);
 
 /* get postscript name from fullname or postscript name */
 const char *afm_get_font_postscript_name ( const char* font);
+const char *afm_get_font_name(const char* font);
 
 /* cc -E -dM /dev/null */
 #ifdef __APPLE__
 /* need charset conversion from macintosh to unicode. */
 extern const unsigned char afm_mac2iso[128];
-#define afm_host2unicode(c) \
-       ( (c) >= 128 ? afm_mac2iso[(c) - 128] : (c))
+#define afm_fix_osx_charset(c) \
+       ( (c) >= 128 && (c) <= 255 ? afm_mac2iso[(c) - 128] : (c))
 #else
 /* UNSAFE macro */
-#define afm_host2unicode(a_unsigned_char) ((unsigned int)(a_unsigned_char))
+#define afm_fix_osx_charset(x) (x)
 #endif
 
 #endif
index 41ebce0ce3c8379b1d0b5aea32c1098523e91fff..fccf58601d689adbf2407856eb78802f99526723 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  ****************************************************************************
  * rrd_afm_data.c  Encoded afm (Adobe Font Metrics) for selected fonts.
  ****************************************************************************
@@ -3223,6 +3223,7 @@ static afm_cunicode afm_Times_Roman_ligatures[] = { /* 3 */
 const afm_fontinfo afm_fontinfolist[] = {
   { /* Courier.afm   761 bytes */
       "Courier", "Courier",
+      629, -157,
       afm_Courier_widths,
       NULL,
       NULL,
@@ -3230,6 +3231,7 @@ const afm_fontinfo afm_fontinfolist[] = {
       afm_Courier_ligatures, 1},
   { /* Courier-Bold.afm   761 bytes */
       "Courier-Bold", "Courier Bold",
+      629, -157,
       afm_Courier_Bold_widths,
       NULL,
       NULL,
@@ -3237,6 +3239,7 @@ const afm_fontinfo afm_fontinfolist[] = {
       afm_Courier_Bold_ligatures, 1},
   { /* Courier-BoldOblique.afm   761 bytes */
       "Courier-BoldOblique", "Courier Bold Oblique",
+      629, -157,
       afm_Courier_BoldOblique_widths,
       NULL,
       NULL,
@@ -3244,6 +3247,7 @@ const afm_fontinfo afm_fontinfolist[] = {
       afm_Courier_BoldOblique_ligatures, 1},
   { /* Courier-Oblique.afm   761 bytes */
       "Courier-Oblique", "Courier Oblique",
+      629, -157,
       afm_Courier_Oblique_widths,
       NULL,
       NULL,
@@ -3251,6 +3255,7 @@ const afm_fontinfo afm_fontinfolist[] = {
       afm_Courier_Oblique_ligatures, 1},
   { /* Helvetica.afm   7841 bytes */
       "Helvetica", "Helvetica",
+      718, -207,
       afm_Helvetica_widths,
       afm_Helvetica_kerning_index,
       afm_Helvetica_kerning_data,
@@ -3258,6 +3263,7 @@ const afm_fontinfo afm_fontinfolist[] = {
       afm_Helvetica_ligatures, 1},
   { /* Helvetica-Bold.afm   7336 bytes */
       "Helvetica-Bold", "Helvetica Bold",
+      718, -207,
       afm_Helvetica_Bold_widths,
       afm_Helvetica_Bold_kerning_index,
       afm_Helvetica_Bold_kerning_data,
@@ -3265,6 +3271,7 @@ const afm_fontinfo afm_fontinfolist[] = {
       afm_Helvetica_Bold_ligatures, 1},
   { /* Helvetica-BoldOblique.afm   7336 bytes */
       "Helvetica-BoldOblique", "Helvetica Bold Oblique",
+      718, -207,
       afm_Helvetica_BoldOblique_widths,
       afm_Helvetica_BoldOblique_kerning_index,
       afm_Helvetica_BoldOblique_kerning_data,
@@ -3272,6 +3279,7 @@ const afm_fontinfo afm_fontinfolist[] = {
       afm_Helvetica_BoldOblique_ligatures, 1},
   { /* Helvetica-Oblique.afm   7841 bytes */
       "Helvetica-Oblique", "Helvetica Oblique",
+      718, -207,
       afm_Helvetica_Oblique_widths,
       afm_Helvetica_Oblique_kerning_index,
       afm_Helvetica_Oblique_kerning_data,
@@ -3279,6 +3287,7 @@ const afm_fontinfo afm_fontinfolist[] = {
       afm_Helvetica_Oblique_ligatures, 1},
   { /* ZapfDingbats.afm   416 bytes */
       "ZapfDingbats", "ITC Zapf Dingbats",
+      0, 0,
       afm_ZapfDingbats_widths,
       NULL,
       NULL,
@@ -3286,6 +3295,7 @@ const afm_fontinfo afm_fontinfolist[] = {
       NULL, 0},
   { /* Symbol.afm   563 bytes */
       "Symbol", "Symbol",
+      0, 0,
       afm_Symbol_widths,
       NULL,
       NULL,
@@ -3293,6 +3303,7 @@ const afm_fontinfo afm_fontinfolist[] = {
       NULL, 0},
   { /* Times-Bold.afm   6761 bytes */
       "Times-Bold", "Times Bold",
+      683, -217,
       afm_Times_Bold_widths,
       afm_Times_Bold_kerning_index,
       afm_Times_Bold_kerning_data,
@@ -3300,6 +3311,7 @@ const afm_fontinfo afm_fontinfolist[] = {
       afm_Times_Bold_ligatures, 1},
   { /* Times-BoldItalic.afm   6270 bytes */
       "Times-BoldItalic", "Times Bold Italic",
+      683, -217,
       afm_Times_BoldItalic_widths,
       afm_Times_BoldItalic_kerning_index,
       afm_Times_BoldItalic_kerning_data,
@@ -3307,6 +3319,7 @@ const afm_fontinfo afm_fontinfolist[] = {
       afm_Times_BoldItalic_ligatures, 1},
   { /* Times-Italic.afm   6975 bytes */
       "Times-Italic", "Times Italic",
+      683, -217,
       afm_Times_Italic_widths,
       afm_Times_Italic_kerning_index,
       afm_Times_Italic_kerning_data,
@@ -3314,11 +3327,12 @@ const afm_fontinfo afm_fontinfolist[] = {
       afm_Times_Italic_ligatures, 1},
   { /* Times-Roman.afm   6287 bytes */
       "Times-Roman", "Times Roman",
+      683, -217,
       afm_Times_Roman_widths,
       afm_Times_Roman_kerning_index,
       afm_Times_Roman_kerning_data,
       afm_Times_Roman_highchars_index, 220,
       afm_Times_Roman_ligatures, 1},
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
 };
 const int afm_fontinfo_count = 14;
index f301f21f7a13e1f10f63192a6f7a541eaa7cfb15..84b142235a0c6f9ee657ada6093dafaf6e4e59d3 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  ****************************************************************************
  * rrd_afm_data.h  Encoded afm (Adobe Font Metrics) for selected fonts.
  ****************************************************************************/
@@ -168,6 +168,7 @@ typedef const afm_unicode afm_cunicode;
 typedef struct afm_fontinfo {
   const char   *fullname; /* e.g. "Futura Bold Oblique" */
   const char   *postscript_name; /* e.g. "Futura-BoldOblique" */
+  afm_cuint16 ascender, descender;
   afm_cuint8   *widths;
   afm_csint16  *kerning_index;
   afm_cuint8   *kerning_data;
index 9f8ef5e0a8b4f316dde0dd0020679b548b57fec8..5c2aa1bc36c1668c5f2a2d47412c19c27b612aad 100644 (file)
@@ -1,20 +1,23 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2004
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_cgi.c  RRD Web Page Generator
  *****************************************************************************/
 
 #include "rrd_tool.h"
-#include <cgi.h>
-#include <time.h>
 
 
 #define MEMBLK 1024
 /*#define DEBUG_PARSER
 #define DEBUG_VARS*/
 
-/* global variable for libcgi */
-s_cgi *cgiArg;
+typedef struct var_s {
+       char    *name, *value;
+} s_var;
+
+typedef struct cgi_s {
+       s_var **vars;
+} s_cgi;
 
 /* in arg[0] find tags beginning with arg[1] call arg[2] on them
    and replace by result of arg[2] call */
@@ -35,7 +38,7 @@ char* cgigetq(long , const char **);
 char* cgigetqp(long , const char **);
 
 /* call rrd_graph and insert appropriate image tag */
-char* drawgraph(long, char **);
+char* drawgraph(long, const char **);
 
 /* return PRINT functions from last rrd_graph call */
 char* drawprint(long, const char **);
@@ -58,6 +61,9 @@ char* includefile(long, const char **);
 /* for how long is the output of the cgi valid ? */
 char* rrdgoodfor(long, const char **);
 
+/* return rrdcgi version string */ 
+char* rrdgetinternal(long, const char **);
+
 char* rrdstrip(char *buf);
 char* scanargs(char *line, int *argc, char ***args);
 
@@ -70,6 +76,64 @@ char *http_time(time_t *);
 /* return a pointer to newly allocated copy of this string */
 char *stralloc(const char *);
 
+/* global variable for rrdcgi */
+s_cgi *rrdcgiArg;
+
+/* rrdcgiHeader
+ * 
+ *  Prints a valid CGI Header (Content-type...) etc.
+ */
+void rrdcgiHeader(void);
+
+/* rrdcgiDecodeString
+ * decode html escapes
+ */
+char *rrdcgiDecodeString(char *text);
+
+/* rrdcgiDebug
+ * 
+ *  Set/unsets debugging
+ */
+void rrdcgiDebug(int level, int where);
+
+/* rrdcgiInit
+ *
+ *  Reads in variables set via POST or stdin.
+ */
+s_cgi *rrdcgiInit (void);
+
+/* rrdcgiGetValue
+ *
+ *  Returns the value of the specified variable or NULL if it's empty
+ *  or doesn't exist.
+ */
+char *rrdcgiGetValue (s_cgi *parms, const char *name);
+
+/* rrdcgiFreeList
+ *
+ * Frees a list as returned by rrdcgiGetVariables()
+ */
+void rrdcgiFreeList (char **list);
+
+/* rrdcgiFree
+ *
+ * Frees the internal data structures
+ */
+void rrdcgiFree (s_cgi *parms);
+
+/*  rrdcgiReadVariables()
+ *
+ *  Read from stdin if no string is provided via CGI.  Variables that
+ *  doesn't have a value associated with it doesn't get stored.
+ */
+s_var **rrdcgiReadVariables(void);
+
+
+int rrdcgiDebugLevel = 0;
+int rrdcgiDebugStderr = 1;
+char *rrdcgiHeaderString = NULL;
+char *rrdcgiType = NULL;
 
 /* rrd interface to the variable functions {put,get}var() */
 char* rrdgetvar(long argc, const char **args);
@@ -223,6 +287,7 @@ rrd_expand_vars(char* buffer)
                 parse(&buffer, i, "<RRD::TIME::LAST", printtimelast);
                 parse(&buffer, i, "<RRD::TIME::NOW", printtimenow);
                 parse(&buffer, i, "<RRD::TIME::STRFTIME", printstrftime);
+               parse(&buffer, i, "<RRD::INTERNAL", rrdgetinternal);
        }
        return buffer;
 }
@@ -266,6 +331,8 @@ int main(int argc, char *argv[]) {
 #ifdef MUST_DISABLE_FPMASK
        fpsetmask(0);
 #endif
+        optind = 0; opterr = 0;  /* initialize getopt */
+
        /* what do we get for cmdline arguments?
        for (i=0;i<argc;i++)
        printf("%d-'%s'\n",i,argv[i]); */
@@ -292,8 +359,8 @@ int main(int argc, char *argv[]) {
        }
 
        if (!filter) {
-               cgiDebug(0,0);
-               cgiArg = cgiInit();
+               rrdcgiDebug(0,0);
+               rrdcgiArg = rrdcgiInit();
                server_url = getenv("SERVER_URL");
        }
 
@@ -346,6 +413,7 @@ int main(int argc, char *argv[]) {
                parse(&buffer, i, "<RRD::TIME::LAST", printtimelast);
                parse(&buffer, i, "<RRD::TIME::NOW", printtimenow);
                parse(&buffer, i, "<RRD::TIME::STRFTIME", printstrftime);
+               parse(&buffer, i, "<RRD::INTERNAL", rrdgetinternal);
        }
 
        if (!filter) {
@@ -443,11 +511,7 @@ char* rrdgetenv(long argc, const char **args) {
        if (envvar) {
                return stralloc(envvar);
        } else {
-#ifdef WIN32
-               _snprintf(buf, sizeof(buf), "[ERROR:_getenv_'%s'_failed", args[0]);
-#else
                 snprintf(buf, sizeof(buf), "[ERROR:_getenv_'%s'_failed", args[0]);
-#endif         
                 return stralloc(buf);
        }
 }
@@ -463,11 +527,7 @@ char* rrdgetvar(long argc, const char **args) {
        if (value) {
                return stralloc(value);
        } else {
-#ifdef WIN32
-               _snprintf(buf, sizeof(buf), "[ERROR:_getvar_'%s'_failed", args[0]);
-#else
                 snprintf(buf, sizeof(buf), "[ERROR:_getvar_'%s'_failed", args[0]);
-#endif
                return stralloc(buf);
        }
 }
@@ -486,6 +546,20 @@ char* rrdgoodfor(long argc, const char **args){
   return stralloc("");
 }
 
+char* rrdgetinternal(long argc, const char **args){
+  if (argc == 1) {
+    if( strcasecmp( args[0], "VERSION") == 0) {
+      return stralloc(PACKAGE_VERSION);
+    } else if( strcasecmp( args[0], "COMPILETIME") == 0) {
+      return stralloc(__DATE__ " " __TIME__);
+    } else {
+      return stralloc("[ERROR: internal unknown argument]");
+    }
+  } else {
+    return stralloc("[ERROR: internal expected 1 argument]");
+  }
+}
+
 /* Format start or end times using strftime.  We always need both the
  * start and end times, because, either might be relative to the other.
  * */
@@ -500,7 +574,7 @@ char* printstrftime(long argc, const char **args){
        /* Make sure that we were given the right number of args */
        if( argc != 4) {
                rrd_set_error( "wrong number of args %d", argc);
-               return (char *) -1;
+               return stralloc("");
        }
 
        /* Init start and end time */
@@ -510,14 +584,14 @@ char* printstrftime(long argc, const char **args){
        /* Parse the start and end times we were given */
        if( (parsetime_error = parsetime( args[1], &start_tv))) {
                rrd_set_error( "start time: %s", parsetime_error);
-               return (char *) -1;
+               return stralloc("");
        }
        if( (parsetime_error = parsetime( args[2], &end_tv))) {
                rrd_set_error( "end time: %s", parsetime_error);
-               return (char *) -1;
+               return stralloc("");
        }
        if( proc_start_end( &start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
-               return (char *) -1;
+               return stralloc("");
        }
 
        /* Do we do the start or end */
@@ -529,7 +603,7 @@ char* printstrftime(long argc, const char **args){
        }
        else {
                rrd_set_error( "start/end not found in '%s'", args[0]);
-               return (char *) -1;
+               return stralloc("");
        }
 
        /* now format it */
@@ -538,14 +612,14 @@ char* printstrftime(long argc, const char **args){
        }
        else {
                rrd_set_error( "strftime failed");
-               return (char *) -1;
+               return stralloc("");
        }
 }
 
 char* includefile(long argc, const char **args){
   char *buffer;
   if (argc >= 1) {
-      char* filename = args[0];
+      const char* filename = args[0];
       readfile(filename, &buffer, 0);
       if (rrd_test_error()) {
                char *err = malloc((strlen(rrd_get_error())+DS_NAM_SIZE));
@@ -586,7 +660,7 @@ char* rrdstrip(char *buf) {
 
 char* cgigetq(long argc, const char **args){
   if (argc>= 1){
-    char *buf = rrdstrip(cgiGetValue(cgiArg,args[0]));
+    char *buf = rrdstrip(rrdcgiGetValue(rrdcgiArg,args[0]));
     char *buf2;
     char *c,*d;
     int  qc=0;
@@ -633,7 +707,7 @@ char* cgigetqp(long argc, const char **args){
                 return stralloc("[ERROR: not enough arguments for RRD::CV::PATH]");
         }
 
-        buf = rrdstrip(cgiGetValue(cgiArg, args[0]));
+        buf = rrdstrip(rrdcgiGetValue(rrdcgiArg, args[0]));
     if (!buf)
         {
                 return NULL;
@@ -680,14 +754,14 @@ char* cgigetqp(long argc, const char **args){
 
 char* cgiget(long argc, const char **args){
   if (argc>= 1)
-    return rrdstrip(cgiGetValue(cgiArg,args[0]));
+    return rrdstrip(rrdcgiGetValue(rrdcgiArg,args[0]));
   else
     return stralloc("[ERROR: not enough arguments for RRD::CV]");
 }
 
 
 
-char* drawgraph(long argc, char **args){
+char* drawgraph(long argc, const char **args){
   int i,xsize, ysize;
   double ymin,ymax;
   for(i=0;i<argc;i++)
@@ -696,10 +770,8 @@ char* drawgraph(long argc, char **args){
     args[argc++] = "--imginfo";
     args[argc++] = "<IMG SRC=\"./%s\" WIDTH=\"%lu\" HEIGHT=\"%lu\">";
   }
-  optind=0; /* reset gnu getopt */
-  opterr=0; /* reset gnu getopt */
   calfree();
-  if( rrd_graph(argc+1, args-1, &calcpr, &xsize, &ysize,NULL,&ymin,&ymax) != -1 ) {
+  if( rrd_graph(argc+1, (char **) args-1, &calcpr, &xsize, &ysize,NULL,&ymin,&ymax) != -1 ) {
     return stralloc(calcpr[0]);
   } else {
     if (rrd_test_error()) {
@@ -732,7 +804,7 @@ char* printtimelast(long argc, const char **args) {
     if (buf == NULL){  
        return stralloc("[ERROR: allocating strftime buffer]");
     };
-    last = rrd_last(argc+1, args-1); 
+    last = rrd_last(argc+1, (char **) args-1); 
     if (rrd_test_error()) {
       char *err = malloc((strlen(rrd_get_error())+DS_NAM_SIZE)*sizeof(char));
       sprintf(err, "[ERROR: %s]",rrd_get_error());
@@ -981,7 +1053,7 @@ parse(
        if (end)
        {
                /* got arguments, call function for 'tag' with arguments */
-               val = func(argc, args);
+               val = func(argc, (const char **) args);
                free(args);
        }
        else
@@ -1048,3 +1120,293 @@ http_time(time_t *now) {
         strftime(buf,sizeof(buf),"%a, %d %b %Y %H:%M:%S GMT",tmptime);
         return(buf);
 }
+
+void rrdcgiHeader(void)
+{
+    if (rrdcgiType)
+       printf ("Content-type: %s\n", rrdcgiType);
+    else
+       printf ("Content-type: text/html\n");
+    if (rrdcgiHeaderString)
+       printf ("%s", rrdcgiHeaderString);
+    printf ("\n");
+}
+
+void rrdcgiDebug(int level, int where)
+{
+    if (level > 0)
+       rrdcgiDebugLevel = level;
+    else
+       rrdcgiDebugLevel = 0;
+    if (where)
+       rrdcgiDebugStderr = 0;
+    else
+       rrdcgiDebugStderr = 1;
+}
+
+char *rrdcgiDecodeString(char *text)
+{
+    char *cp, *xp;
+
+    for (cp=text,xp=text; *cp; cp++) {
+       if (*cp == '%') {
+           if (strchr("0123456789ABCDEFabcdef", *(cp+1))
+               && strchr("0123456789ABCDEFabcdef", *(cp+2))) {
+               if (islower(*(cp+1)))
+                   *(cp+1) = toupper(*(cp+1));
+               if (islower(*(cp+2)))
+                   *(cp+2) = toupper(*(cp+2));
+               *(xp) = (*(cp+1) >= 'A' ? *(cp+1) - 'A' + 10 : *(cp+1) - '0' ) * 16
+                   + (*(cp+2) >= 'A' ? *(cp+2) - 'A' + 10 : *(cp+2) - '0');
+               xp++;cp+=2;
+           }
+       } else {
+           *(xp++) = *cp;
+       }
+    }
+    memset(xp, 0, cp-xp);
+    return text;
+}
+
+/*  rrdcgiReadVariables()
+ *
+ *  Read from stdin if no string is provided via CGI.  Variables that
+ *  doesn't have a value associated with it doesn't get stored.
+ */
+s_var **rrdcgiReadVariables(void)
+{
+    int length;
+    char *line = NULL;
+    int numargs;
+    char *cp, *ip, *esp, *sptr;
+    s_var **result;
+    int i, k, len;
+    char tmp[101];
+
+    cp = getenv("REQUEST_METHOD");
+    ip = getenv("CONTENT_LENGTH");
+
+    if (cp && !strcmp(cp, "POST")) {
+       if (ip) {
+           length = atoi(ip);
+           if ((line = (char *)malloc (length+2)) == NULL)
+               return NULL;
+           fgets(line, length+1, stdin);
+       } else
+           return NULL;
+    } else if (cp && !strcmp(cp, "GET")) {
+       esp = getenv("QUERY_STRING");
+       if (esp && strlen(esp)) {
+           if ((line = (char *)malloc (strlen(esp)+2)) == NULL)
+               return NULL;
+           sprintf (line, "%s", esp);
+       } else
+           return NULL;
+    } else {
+        length = 0;
+       printf ("(offline mode: enter name=value pairs on standard input)\n");
+       memset (tmp, 0, sizeof(tmp));
+       while((cp = fgets (tmp, 100, stdin)) != NULL) {
+           if (strlen(tmp)) {
+               if (tmp[strlen(tmp)-1] == '\n')
+                   tmp[strlen(tmp)-1] = '&';
+               if (length) {
+                   length += strlen(tmp);
+                   len = (length+1) * sizeof(char);
+                   if ((line = (char *)realloc (line, len)) == NULL)
+                       return NULL;
+                   strcat (line, tmp);
+               } else {
+                   length = strlen(tmp);
+                   len = (length+1) * sizeof(char);
+                   if ((line = (char *)malloc (len)) == NULL)
+                       return NULL;
+                   memset (line, 0, len);
+                   strcpy (line, tmp);
+               }
+           }
+           memset (tmp, 0, sizeof(tmp));
+       }
+       if (!line)
+           return NULL;
+       if (line[strlen(line)-1] == '&')
+           line[strlen(line)-1] = '\0';
+    }
+
+    /*
+     *  From now on all cgi variables are stored in the variable line
+     *  and look like  foo=bar&foobar=barfoo&foofoo=
+     */
+
+    if (rrdcgiDebugLevel > 0) {
+       if (rrdcgiDebugStderr)
+           fprintf (stderr, "Received cgi input: %s\n", line);
+       else
+           printf ("<b>Received cgi input</b><br>\n<pre>\n--\n%s\n--\n</pre>\n\n", line);
+    }
+
+    for (cp=line; *cp; cp++)
+       if (*cp == '+')
+           *cp = ' ';
+
+    if (strlen(line)) {
+       for (numargs=1,cp=line; *cp; cp++)
+           if (*cp == '&') numargs++;
+    } else
+       numargs = 0;
+    if (rrdcgiDebugLevel > 0) {
+       if (rrdcgiDebugStderr)
+           fprintf (stderr, "%d cgi variables found.\n", numargs);
+       else
+           printf ("%d cgi variables found.<br>\n", numargs);
+    }
+
+    len = (numargs+1) * sizeof(s_var *);
+    if ((result = (s_var **)malloc (len)) == NULL)
+       return NULL;
+    memset (result, 0, len);
+
+    cp = line;
+    i=0;
+    while (*cp) {
+       if ((ip = (char *)strchr(cp, '&')) != NULL) {
+           *ip = '\0';
+       }else
+           ip = cp + strlen(cp);
+
+       if ((esp=(char *)strchr(cp, '=')) == NULL) {
+           cp = ++ip;
+           continue;
+       }
+
+       if (!strlen(esp)) {
+           cp = ++ip;
+           continue;
+       }
+
+       if (i<numargs) {
+
+           /* try to find out if there's already such a variable */
+           for (k=0; k<i && (strncmp (result[k]->name,cp, esp-cp) || !(strlen (result[k]->name) == esp-cp)); k++);
+
+           if (k == i) {       /* No such variable yet */
+               if ((result[i] = (s_var *)malloc(sizeof(s_var))) == NULL)
+                   return NULL;
+               if ((result[i]->name = (char *)malloc((esp-cp+1) * sizeof(char))) == NULL)
+                   return NULL;
+               memset (result[i]->name, 0, esp-cp+1);
+               strncpy(result[i]->name, cp, esp-cp);
+               cp = ++esp;
+               if ((result[i]->value = (char *)malloc((ip-esp+1) * sizeof(char))) == NULL)
+                   return NULL;
+               memset (result[i]->value, 0, ip-esp+1);
+               strncpy(result[i]->value, cp, ip-esp);
+               result[i]->value = rrdcgiDecodeString(result[i]->value);
+               if (rrdcgiDebugLevel) {
+                   if (rrdcgiDebugStderr)
+                       fprintf (stderr, "%s: %s\n", result[i]->name, result[i]->value);
+                   else
+                       printf ("<h3>Variable %s</h3>\n<pre>\n%s\n</pre>\n\n", result[i]->name, result[i]->value);
+               }
+               i++;
+           } else {    /* There is already such a name, suppose a mutiple field */
+               cp = ++esp;
+               len = (strlen(result[k]->value)+(ip-esp)+2) * sizeof (char);
+               if ((sptr = (char *)malloc(len)) == NULL)
+                   return NULL;
+               memset (sptr, 0, len);
+               sprintf (sptr, "%s\n", result[k]->value);
+               strncat(sptr, cp, ip-esp);
+               free(result[k]->value);
+               result[k]->value = rrdcgiDecodeString (sptr);
+           }
+       }
+       cp = ++ip;
+    }
+    return result;
+}
+
+/*  rrdcgiInit()
+ *
+ *  Read from stdin if no string is provided via CGI.  Variables that
+ *  doesn't have a value associated with it doesn't get stored.
+ */
+s_cgi *rrdcgiInit(void)
+{
+    s_cgi *res;
+    s_var **vars;
+
+    vars = rrdcgiReadVariables();
+
+    if (!vars)
+       return NULL;
+
+    if ((res = (s_cgi *)malloc (sizeof (s_cgi))) == NULL)
+       return NULL;
+    res->vars = vars;
+
+    return res;
+}
+
+char *rrdcgiGetValue(s_cgi *parms, const char *name)
+{
+    int i;
+
+    if (!parms || !parms->vars)
+       return NULL;
+    for (i=0;parms->vars[i]; i++)
+       if (!strcmp(name,parms->vars[i]->name)) {
+           if (rrdcgiDebugLevel > 0) {
+               if (rrdcgiDebugStderr)
+                   fprintf (stderr, "%s found as %s\n", name, parms->vars[i]->value);
+               else
+                   printf ("%s found as %s<br>\n", name, parms->vars[i]->value);
+           }
+           return parms->vars[i]->value;
+       }
+    if (rrdcgiDebugLevel) {
+       if (rrdcgiDebugStderr)
+           fprintf (stderr, "%s not found\n", name);
+       else
+           printf ("%s not found<br>\n", name);
+    }
+    return NULL;
+}
+
+void rrdcgiFreeList (char **list)
+{
+    int i;
+
+    for (i=0; list[i] != NULL; i++)
+       free (list[i]);
+       free (list);
+}
+
+void rrdcgiFree (s_cgi *parms)
+{
+    int i;
+
+    if (!parms)
+       return;
+    if (parms->vars) {
+               for (i=0;parms->vars[i]; i++) {
+                       if (parms->vars[i]->name)
+                               free (parms->vars[i]->name);
+                       if (parms->vars[i]->value)
+                               free (parms->vars[i]->value);
+           free (parms->vars[i]);
+               }
+               free (parms->vars);
+    }
+    free (parms);
+
+    if (rrdcgiHeaderString) {
+       free (rrdcgiHeaderString);
+       rrdcgiHeaderString = NULL;
+    }
+    if (rrdcgiType) {
+       free (rrdcgiType);
+       rrdcgiType = NULL;
+    }
+}
+
index 90c38d338e9056d57e91f2152c9fc5cf0562d3cc..e9ac860dca92c184f1012e5617076933b3dcdb99 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_create.c  creates new rrds
  *****************************************************************************/
@@ -10,9 +10,9 @@
 
 #include "rrd_is_thread_safe.h"
 
-unsigned long FnvHash(char *str);
+unsigned long FnvHash(const char *str);
 int create_hw_contingent_rras(rrd_t *rrd, unsigned short period, unsigned long hashed_name);
-void parseGENERIC_DS(char *def,rrd_t *rrd, int ds_idx);
+void parseGENERIC_DS(const char *def,rrd_t *rrd, int ds_idx);
 
 int
 rrd_create(int argc, char **argv) 
@@ -23,6 +23,7 @@ rrd_create(int argc, char **argv)
     char *parsetime_error = NULL;
     long              long_tmp;
     int               rc;
+    optind = 0; opterr = 0;  /* initialize getopt */
 
     while (1){
        static struct option long_options[] =
@@ -77,24 +78,28 @@ rrd_create(int argc, char **argv)
            return(-1);
        }
     }
-
+    if (optind == argc) {
+         rrd_set_error("what is the name of the rrd file you want to create?");
+         return -1;
+    }
     rc = rrd_create_r(argv[optind],
                      pdp_step, last_up,
-                     argc - optind - 1, argv + optind + 1);
+                     argc - optind - 1, (const char **)(argv + optind + 1));
     
     return rc;
 }
 
 /* #define DEBUG */
 int
-rrd_create_r(char *filename,
+rrd_create_r(const char *filename,
             unsigned long pdp_step, time_t last_up,
-            int argc, char **argv) 
+            int argc, const char **argv) 
 {
     rrd_t             rrd;
     long              i;
     int               offset;
     char *token;
+    char dummychar1[2], dummychar2[2];
     unsigned short token_idx, error_flag, period=0;
     unsigned long hashed_name;
 
@@ -145,19 +150,31 @@ rrd_create_r(char *filename,
            }
            memset(&rrd.ds_def[rrd.stat_head->ds_cnt], 0, sizeof(ds_def_t));
             /* extract the name and type */
-           if (sscanf(&argv[i][3],
-                      DS_NAM_FMT ":" DST_FMT ":%n",
-                      rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
-                      rrd.ds_def[rrd.stat_head->ds_cnt].dst,&offset) == 2)
-            {
-                /* check for duplicate datasource names */
-                for(ii=0;ii<rrd.stat_head->ds_cnt;ii++)
-                    if(strcmp(rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
-                              rrd.ds_def[ii].ds_nam) == 0){
-                        rrd_set_error("Duplicate DS name: %s",rrd.ds_def[ii].ds_nam);
-                    }                                                          
-            } else {
-                rrd_set_error("invalid DS format");
+           switch (sscanf(&argv[i][3],
+                       DS_NAM_FMT "%1[:]" DST_FMT "%1[:]%n",
+                       rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
+                       dummychar1,
+                       rrd.ds_def[rrd.stat_head->ds_cnt].dst,
+                       dummychar2,
+                       &offset)) {
+               case 0:
+               case 1: rrd_set_error("Invalid DS name"); break;
+               case 2:
+               case 3: rrd_set_error("Invalid DS type"); break;
+               case 4: /* (%n may or may not be counted) */
+               case 5: /* check for duplicate datasource names */
+                   for (ii=0;ii<rrd.stat_head->ds_cnt;ii++)
+                       if(strcmp(rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
+                               rrd.ds_def[ii].ds_nam) == 0)
+                           rrd_set_error("Duplicate DS name: %s",
+                                       rrd.ds_def[ii].ds_nam);
+                   /* DS_type may be valid or not. Checked later */
+                   break;
+               default: rrd_set_error("invalid DS format");
+            }
+           if (rrd_test_error()) {
+                rrd_free(&rrd);
+                return -1;
             }
             
             /* parse the remainder of the arguments */
@@ -182,7 +199,8 @@ rrd_create_r(char *filename,
                 return -1;
             }
             rrd.stat_head -> ds_cnt++;
-       } else if (strncmp(argv[i],"RRA:",3)==0){
+       } else if (strncmp(argv[i],"RRA:",4)==0){
+            char *argvcopy;
            char *tokptr;
            size_t old_size = sizeof(rra_def_t)*(rrd.stat_head->rra_cnt);
            if((rrd.rra_def = rrd_realloc(rrd.rra_def,
@@ -193,8 +211,9 @@ rrd_create_r(char *filename,
                 return(-1);    
            }
            memset(&rrd.rra_def[rrd.stat_head->rra_cnt], 0, sizeof(rra_def_t));
-            
-           token = strtok_r(&argv[i][4],":", &tokptr);
+
+            argvcopy = strdup(argv[i]);
+           token = strtok_r(&argvcopy[4],":", &tokptr);
            token_idx = error_flag = 0;
            while (token != NULL)
            {
@@ -369,12 +388,14 @@ rrd_create_r(char *filename,
                 if (rrd_test_error())
                 {
                     /* all errors are unrecoverable */
+                    free(argvcopy);
                     rrd_free(&rrd);
                     return (-1);
                 }
                 token = strtok_r(NULL,":", &tokptr);
                 token_idx++;
            } /* end while */
+           free(argvcopy);
 #ifdef DEBUG
            fprintf(stderr,"Creating RRA CF: %s, dep idx %lu, current idx %lu\n",
                    rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam,
@@ -418,7 +439,7 @@ rrd_create_r(char *filename,
     return rrd_create_fn(filename, &rrd);
 }
 
-void parseGENERIC_DS(char *def,rrd_t *rrd, int ds_idx)
+void parseGENERIC_DS(const char *def,rrd_t *rrd, int ds_idx)
 {
     char minstr[DS_NAM_SIZE], maxstr[DS_NAM_SIZE];     
     /*
@@ -526,18 +547,23 @@ create_hw_contingent_rras(rrd_t *rrd, unsigned short period, unsigned long hashe
 /* create and empty rrd file according to the specs given */
 
 int
-rrd_create_fn(char *file_name, rrd_t *rrd)
+rrd_create_fn(const char *file_name, rrd_t *rrd)
 {
     unsigned long    i,ii;
     FILE             *rrd_file;
     rrd_value_t      *unknown;
     int        unkn_cnt;
-    
+
+    long rrd_head_size;
+
     if ((rrd_file = fopen(file_name,"wb")) == NULL ) {
        rrd_set_error("creating '%s': %s",file_name, rrd_strerror(errno));
        free(rrd->stat_head);
+        rrd->stat_head = NULL; 
        free(rrd->ds_def);
+        rrd->ds_def = NULL; 
        free(rrd->rra_def);
+        rrd->rra_def = NULL;
        return(-1);
     }
     
@@ -634,7 +660,8 @@ rrd_create_fn(char *file_name, rrd_t *rrd)
         rrd->rra_ptr->cur_row = rrd->rra_def[i].row_cnt - 1;
         fwrite( rrd->rra_ptr, sizeof(rra_ptr_t),1,rrd_file);
     }
-    
+    rrd_head_size = ftell(rrd_file);
+
     /* write the empty data area */
     if ((unknown = (rrd_value_t *)malloc(512 * sizeof(rrd_value_t))) == NULL) {
        rrd_set_error("allocating unknown");
@@ -663,6 +690,24 @@ rrd_create_fn(char *file_name, rrd_t *rrd)
        return(-1);
     }
     
+#ifdef HAVE_POSIX_FADVISE
+    /* this file is not going to be read again any time
+       soon, so we drop everything except the header portion from
+       the buffer cache. for this to work, we have to fdsync the file
+       first though. This will not be all that fast, but 'good' data
+       like other rrdfiles headers will stay in cache. Now this only works if creating
+       a single rrd file is not too large, but I assume this should not be the case
+       in general. Otherwhise we would have to sync and release while writing all
+       the unknown data. */
+    fflush(rrd_file);
+    fdatasync(fileno(rrd_file));
+    if (0 != posix_fadvise(fileno(rrd_file), rrd_head_size, 0, POSIX_FADV_DONTNEED)) {
+        rrd_set_error("setting POSIX_FADV_DONTNEED on '%s': %s",file_name, rrd_strerror(errno));
+        fclose(rrd_file);
+        return(-1);
+    }    
+#endif
+
     fclose(rrd_file);    
     rrd_free(rrd);
     return (0);
index fd5d883210aa70f6ca773279244a9fe0285ee4af..42e870c34ee03257ac1e49a950541d193e4e9790 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_datalang  A system for passing named and typed parameters between
  *               the different parts of rrdtool
index c7c11f93a42dc32f61fb7925e48026adab7008eb..22cef90eb776b1e1e90b0d84afdba62e67dbb4b9 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1999
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  * This code is stolen from rateup (mrtg-2.x) by Dave Rand
  *****************************************************************************
  * diff calculate the difference between two very long integers available as
index a8887ee82ab8ff4b0a6b5ed802c72f9f3b181c68..c8cc7eef5868f13f3af4c744722a26ec10f172a3 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2004
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_dump  Display a RRD
  *****************************************************************************
  * checkin
  *
  *****************************************************************************/
-
 #include "rrd_tool.h"
 #include "rrd_rpncalc.h"
 
+#if !(defined(NETWARE) || defined(WIN32))
 extern char *tzname[2];
+#endif
 
 int
 rrd_dump(int argc, char **argv) 
@@ -57,13 +58,20 @@ rrd_dump(int argc, char **argv)
        return -1;
     }
 
-    rc = rrd_dump_r(argv[1]);
-    
+    if (argc == 3)
+    {
+      rc = rrd_dump_r(argv[1], argv[2]);
+    }
+    else
+    {
+      rc = rrd_dump_r(argv[1], NULL);                  
+    }
+
     return rc;
 }
 
 int
-rrd_dump_r(char *filename)    
+rrd_dump_r(const char *filename, char *outname)    
 {   
     unsigned int i,ii,ix,iii=0;
     time_t       now;
@@ -71,6 +79,7 @@ rrd_dump_r(char *filename)
     rrd_value_t  my_cdp;
     long         rra_base, rra_start, rra_next;
     FILE        *in_file;
+               FILE                            *out_file;
     rrd_t        rrd;
     rrd_value_t  value;
     struct tm    tm;
@@ -79,10 +88,23 @@ rrd_dump_r(char *filename)
        return(-1);
     }
 
-    puts("<!-- Round Robin Database Dump -->");
-    puts("<rrd>");
-    printf("\t<version> %s </version>\n",RRD_VERSION);
-    printf("\t<step> %lu </step> <!-- Seconds -->\n",rrd.stat_head->pdp_step);
+    out_file = NULL;
+    if (outname)
+    {
+      if (!(out_file = fopen(outname, "w")))
+      {
+        return (-1);     
+      }
+    }
+    else 
+    {
+      out_file = stdout;
+    }
+               
+    fputs("<!-- Round Robin Database Dump -->", out_file);
+    fputs("<rrd>", out_file);
+    fprintf(out_file, "\t<version> %s </version>\n",RRD_VERSION);
+    fprintf(out_file, "\t<step> %lu </step> <!-- Seconds -->\n",rrd.stat_head->pdp_step);
 #if HAVE_STRFTIME
     localtime_r(&rrd.live_head->last_up, &tm);
     strftime(somestring,200,"%Y-%m-%d %H:%M:%S %Z",
@@ -90,44 +112,44 @@ rrd_dump_r(char *filename)
 #else
 # error "Need strftime"
 #endif
-    printf("\t<lastupdate> %ld </lastupdate> <!-- %s -->\n\n",
+    fprintf(out_file, "\t<lastupdate> %ld </lastupdate> <!-- %s -->\n\n",
           rrd.live_head->last_up,somestring);
     for(i=0;i<rrd.stat_head->ds_cnt;i++){
-       printf("\t<ds>\n");
-       printf("\t\t<name> %s </name>\n",rrd.ds_def[i].ds_nam);
-       printf("\t\t<type> %s </type>\n",rrd.ds_def[i].dst);
-    if (dst_conv(rrd.ds_def[i].dst) != DST_CDEF) {
-       printf("\t\t<minimal_heartbeat> %lu </minimal_heartbeat>\n",rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt);
-       if (isnan(rrd.ds_def[i].par[DS_min_val].u_val)){
-         printf("\t\t<min> NaN </min>\n");
-       } else {
-         printf("\t\t<min> %0.10e </min>\n",rrd.ds_def[i].par[DS_min_val].u_val);
-       }
-       if (isnan(rrd.ds_def[i].par[DS_max_val].u_val)){
-         printf("\t\t<max> NaN </max>\n");
-       } else {
-         printf("\t\t<max> %0.10e </max>\n",rrd.ds_def[i].par[DS_max_val].u_val);
-       }
-    } else { /* DST_CDEF */
-         char *str;
-         rpn_compact2str((rpn_cdefds_t *) &(rrd.ds_def[i].par[DS_cdef]),rrd.ds_def,&str);
-         printf("\t\t<cdef> %s </cdef>\n", str);
-         free(str);
-       }
-       printf("\n\t\t<!-- PDP Status -->\n");
-       printf("\t\t<last_ds> %s </last_ds>\n",rrd.pdp_prep[i].last_ds);
-       if (isnan(rrd.pdp_prep[i].scratch[PDP_val].u_val)){
-         printf("\t\t<value> NaN </value>\n");
-       } else {
-         printf("\t\t<value> %0.10e </value>\n",rrd.pdp_prep[i].scratch[PDP_val].u_val);
-       }
-       printf("\t\t<unknown_sec> %lu </unknown_sec>\n",
-              rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt);
+          fprintf(out_file, "\t<ds>\n");
+          fprintf(out_file, "\t\t<name> %s </name>\n",rrd.ds_def[i].ds_nam);
+          fprintf(out_file, "\t\t<type> %s </type>\n",rrd.ds_def[i].dst);
+       if (dst_conv(rrd.ds_def[i].dst) != DST_CDEF) {
+          fprintf(out_file, "\t\t<minimal_heartbeat> %lu </minimal_heartbeat>\n",rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt);
+             if (isnan(rrd.ds_def[i].par[DS_min_val].u_val)){
+                 fprintf(out_file, "\t\t<min> NaN </min>\n");
+             } else {
+                 fprintf(out_file, "\t\t<min> %0.10e </min>\n",rrd.ds_def[i].par[DS_min_val].u_val);
+             }
+             if (isnan(rrd.ds_def[i].par[DS_max_val].u_val)){
+                 fprintf(out_file, "\t\t<max> NaN </max>\n");
+             } else {
+                 fprintf(out_file, "\t\t<max> %0.10e </max>\n",rrd.ds_def[i].par[DS_max_val].u_val);
+             }
+       } else { /* DST_CDEF */
+             char *str=NULL;
+             rpn_compact2str((rpn_cdefds_t *) &(rrd.ds_def[i].par[DS_cdef]),rrd.ds_def,&str);
+             fprintf(out_file, "\t\t<cdef> %s </cdef>\n", str);
+             free(str);
+          }
+          fprintf(out_file, "\n\t\t<!-- PDP Status -->\n");
+          fprintf(out_file, "\t\t<last_ds> %s </last_ds>\n",rrd.pdp_prep[i].last_ds);
+          if (isnan(rrd.pdp_prep[i].scratch[PDP_val].u_val)){
+             fprintf(out_file, "\t\t<value> NaN </value>\n");
+          } else {
+             fprintf(out_file, "\t\t<value> %0.10e </value>\n",rrd.pdp_prep[i].scratch[PDP_val].u_val);
+          }
+             fprintf(out_file, "\t\t<unknown_sec> %lu </unknown_sec>\n",
+                     rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt);
        
-       printf("\t</ds>\n\n");
-    }
+             fprintf(out_file, "\t</ds>\n\n");
+       }
 
-    puts("<!-- Round Robin Archives -->");
+    fputs("<!-- Round Robin Archives -->", out_file);
 
     rra_base=ftell(in_file);    
     rra_next = rra_base;
@@ -139,43 +161,43 @@ rrd_dump_r(char *filename)
        rra_next +=  ( rrd.stat_head->ds_cnt
                       * rrd.rra_def[i].row_cnt
                       * sizeof(rrd_value_t));
-       printf("\t<rra>\n");
-       printf("\t\t<cf> %s </cf>\n",rrd.rra_def[i].cf_nam);
-       printf("\t\t<pdp_per_row> %lu </pdp_per_row> <!-- %lu seconds -->\n\n",
+       fprintf(out_file, "\t<rra>\n");
+       fprintf(out_file, "\t\t<cf> %s </cf>\n",rrd.rra_def[i].cf_nam);
+       fprintf(out_file, "\t\t<pdp_per_row> %lu </pdp_per_row> <!-- %lu seconds -->\n\n",
               rrd.rra_def[i].pdp_cnt, rrd.rra_def[i].pdp_cnt
               *rrd.stat_head->pdp_step);
        /* support for RRA parameters */
-       printf("\t\t<params>\n");
+       fprintf(out_file, "\t\t<params>\n");
        switch(cf_conv(rrd.rra_def[i].cf_nam)) {
        case CF_HWPREDICT:
-          printf("\t\t<hw_alpha> %0.10e </hw_alpha>\n", 
+          fprintf(out_file, "\t\t<hw_alpha> %0.10e </hw_alpha>\n", 
                  rrd.rra_def[i].par[RRA_hw_alpha].u_val);
-          printf("\t\t<hw_beta> %0.10e </hw_beta>\n", 
+          fprintf(out_file, "\t\t<hw_beta> %0.10e </hw_beta>\n", 
                  rrd.rra_def[i].par[RRA_hw_beta].u_val);
-          printf("\t\t<dependent_rra_idx> %lu </dependent_rra_idx>\n",
+          fprintf(out_file, "\t\t<dependent_rra_idx> %lu </dependent_rra_idx>\n",
                  rrd.rra_def[i].par[RRA_dependent_rra_idx].u_cnt);
           break;
        case CF_SEASONAL:
        case CF_DEVSEASONAL:
-          printf("\t\t<seasonal_gamma> %0.10e </seasonal_gamma>\n", 
+          fprintf(out_file, "\t\t<seasonal_gamma> %0.10e </seasonal_gamma>\n", 
                  rrd.rra_def[i].par[RRA_seasonal_gamma].u_val);
-          printf("\t\t<seasonal_smooth_idx> %lu </seasonal_smooth_idx>\n",
+          fprintf(out_file, "\t\t<seasonal_smooth_idx> %lu </seasonal_smooth_idx>\n",
                  rrd.rra_def[i].par[RRA_seasonal_smooth_idx].u_cnt);
-          printf("\t\t<dependent_rra_idx> %lu </dependent_rra_idx>\n",
+          fprintf(out_file, "\t\t<dependent_rra_idx> %lu </dependent_rra_idx>\n",
                  rrd.rra_def[i].par[RRA_dependent_rra_idx].u_cnt);
           break;
        case CF_FAILURES:
-          printf("\t\t<delta_pos> %0.10e </delta_pos>\n", 
+          fprintf(out_file, "\t\t<delta_pos> %0.10e </delta_pos>\n", 
                  rrd.rra_def[i].par[RRA_delta_pos].u_val);
-          printf("\t\t<delta_neg> %0.10e </delta_neg>\n", 
+          fprintf(out_file, "\t\t<delta_neg> %0.10e </delta_neg>\n", 
                  rrd.rra_def[i].par[RRA_delta_neg].u_val);
-          printf("\t\t<window_len> %lu </window_len>\n",
+          fprintf(out_file, "\t\t<window_len> %lu </window_len>\n",
                  rrd.rra_def[i].par[RRA_window_len].u_cnt);
-          printf("\t\t<failure_threshold> %lu </failure_threshold>\n",
+          fprintf(out_file, "\t\t<failure_threshold> %lu </failure_threshold>\n",
                  rrd.rra_def[i].par[RRA_failure_threshold].u_cnt);
                  /* fall thru */
        case CF_DEVPREDICT:
-          printf("\t\t<dependent_rra_idx> %lu </dependent_rra_idx>\n",
+          fprintf(out_file, "\t\t<dependent_rra_idx> %lu </dependent_rra_idx>\n",
                  rrd.rra_def[i].par[RRA_dependent_rra_idx].u_cnt);
           break;
        case CF_AVERAGE:
@@ -183,14 +205,14 @@ rrd_dump_r(char *filename)
        case CF_MINIMUM:
        case CF_LAST:
        default:
-          printf("\t\t<xff> %0.10e </xff>\n", rrd.rra_def[i].par[RRA_cdp_xff_val].u_val);
+          fprintf(out_file, "\t\t<xff> %0.10e </xff>\n", rrd.rra_def[i].par[RRA_cdp_xff_val].u_val);
           break;
        }
-       printf("\t\t</params>\n");
-       printf("\t\t<cdp_prep>\n");
+       fprintf(out_file, "\t\t</params>\n");
+       fprintf(out_file, "\t\t<cdp_prep>\n");
        for(ii=0;ii<rrd.stat_head->ds_cnt;ii++){
                unsigned long ivalue;
-               printf("\t\t\t<ds>\n");
+               fprintf(out_file, "\t\t\t<ds>\n");
                /* support for exporting all CDP parameters */
                /* parameters common to all CFs */
                    /* primary_val and secondary_val do not need to be saved between updates
@@ -199,63 +221,63 @@ rrd_dump_r(char *filename)
                value = rrd.cdp_prep[i*rrd.stat_head->ds_cnt
                           +ii].scratch[CDP_primary_val].u_val;
                        if (isnan(value)) {
-                          printf("\t\t\t<primary_value> NaN </primary_value>\n");
+                          fprintf(out_file, "\t\t\t<primary_value> NaN </primary_value>\n");
                        } else {
-                          printf("\t\t\t<primary_value> %0.10e </primary_value>\n", value);
+                          fprintf(out_file, "\t\t\t<primary_value> %0.10e </primary_value>\n", value);
                        }
                value = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_secondary_val].u_val;
                        if (isnan(value)) {
-                          printf("\t\t\t<secondary_value> NaN </secondary_value>\n");
+                          fprintf(out_file, "\t\t\t<secondary_value> NaN </secondary_value>\n");
                        } else {
-                          printf("\t\t\t<secondary_value> %0.10e </secondary_value>\n", value);
+                          fprintf(out_file, "\t\t\t<secondary_value> %0.10e </secondary_value>\n", value);
                        }
                switch(cf_conv(rrd.rra_def[i].cf_nam)) {
                case CF_HWPREDICT:
                value = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_hw_intercept].u_val;
                        if (isnan(value)) {
-                          printf("\t\t\t<intercept> NaN </intercept>\n");
+                          fprintf(out_file, "\t\t\t<intercept> NaN </intercept>\n");
                        } else {
-                          printf("\t\t\t<intercept> %0.10e </intercept>\n", value);
+                          fprintf(out_file, "\t\t\t<intercept> %0.10e </intercept>\n", value);
                        }
                value = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_hw_last_intercept].u_val;
                        if (isnan(value)) {
-                          printf("\t\t\t<last_intercept> NaN </last_intercept>\n");
+                          fprintf(out_file, "\t\t\t<last_intercept> NaN </last_intercept>\n");
                        } else {
-                          printf("\t\t\t<last_intercept> %0.10e </last_intercept>\n", value);
+                          fprintf(out_file, "\t\t\t<last_intercept> %0.10e </last_intercept>\n", value);
                        }
                value = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_hw_slope].u_val;
                        if (isnan(value)) {
-                          printf("\t\t\t<slope> NaN </slope>\n");
+                          fprintf(out_file, "\t\t\t<slope> NaN </slope>\n");
                        } else {
-                          printf("\t\t\t<slope> %0.10e </slope>\n", value);
+                          fprintf(out_file, "\t\t\t<slope> %0.10e </slope>\n", value);
                        }
                value = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_hw_last_slope].u_val;
                        if (isnan(value)) {
-                          printf("\t\t\t<last_slope> NaN </last_slope>\n");
+                          fprintf(out_file, "\t\t\t<last_slope> NaN </last_slope>\n");
                        } else {
-                          printf("\t\t\t<last_slope> %0.10e </last_slope>\n", value);
+                          fprintf(out_file, "\t\t\t<last_slope> %0.10e </last_slope>\n", value);
                        }
                        ivalue = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_null_count].u_cnt;
-                       printf("\t\t\t<nan_count> %lu </nan_count>\n", ivalue);
+                       fprintf(out_file, "\t\t\t<nan_count> %lu </nan_count>\n", ivalue);
                        ivalue = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_last_null_count].u_cnt;
-                       printf("\t\t\t<last_nan_count> %lu </last_nan_count>\n", ivalue);
+                       fprintf(out_file, "\t\t\t<last_nan_count> %lu </last_nan_count>\n", ivalue);
                        break;
                case CF_SEASONAL:
                case CF_DEVSEASONAL:
                value = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_hw_seasonal].u_val;
                        if (isnan(value)) {
-                          printf("\t\t\t<seasonal> NaN </seasonal>\n");
+                          fprintf(out_file, "\t\t\t<seasonal> NaN </seasonal>\n");
                        } else {
-                          printf("\t\t\t<seasonal> %0.10e </seasonal>\n", value);
+                          fprintf(out_file, "\t\t\t<seasonal> %0.10e </seasonal>\n", value);
                        }
                value = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_hw_last_seasonal].u_val;
                        if (isnan(value)) {
-                          printf("\t\t\t<last_seasonal> NaN </last_seasonal>\n");
+                          fprintf(out_file, "\t\t\t<last_seasonal> NaN </last_seasonal>\n");
                        } else {
-                          printf("\t\t\t<last_seasonal> %0.10e </last_seasonal>\n", value);
+                          fprintf(out_file, "\t\t\t<last_seasonal> %0.10e </last_seasonal>\n", value);
                        }
                ivalue = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_init_seasonal].u_cnt;
-                       printf("\t\t\t<init_flag> %lu </init_flag>\n", ivalue);
+                       fprintf(out_file, "\t\t\t<init_flag> %lu </init_flag>\n", ivalue);
                        break;
                case CF_DEVPREDICT:
                        break;
@@ -264,12 +286,12 @@ rrd_dump_r(char *filename)
             unsigned short vidx;
                        char *violations_array = (char *) ((void*) 
                           rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch);
-                       printf("\t\t\t<history> ");
+                       fprintf(out_file, "\t\t\t<history> ");
                        for (vidx = 0; vidx < rrd.rra_def[i].par[RRA_window_len].u_cnt; ++vidx)
                        {
-                               printf("%d",violations_array[vidx]);
+                               fprintf(out_file, "%d",violations_array[vidx]);
                        }
-                       printf(" </history>\n");
+                       fprintf(out_file, " </history>\n");
                        }
                        break;
                case CF_AVERAGE:
@@ -279,19 +301,19 @@ rrd_dump_r(char *filename)
                default:
                value = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_val].u_val;
                        if (isnan(value)) {
-                          printf("\t\t\t<value> NaN </value>\n");
+                          fprintf(out_file, "\t\t\t<value> NaN </value>\n");
                        } else {
-                          printf("\t\t\t<value> %0.10e </value>\n", value);
+                          fprintf(out_file, "\t\t\t<value> %0.10e </value>\n", value);
                        }
-                   printf("\t\t\t<unknown_datapoints> %lu </unknown_datapoints>\n",
+                   fprintf(out_file, "\t\t\t<unknown_datapoints> %lu </unknown_datapoints>\n",
                       rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_unkn_pdp_cnt].u_cnt);
                        break;
                }
-        printf("\t\t\t</ds>\n");        
+        fprintf(out_file, "\t\t\t</ds>\n");     
     }
-       printf("\t\t</cdp_prep>\n");
+       fprintf(out_file, "\t\t</cdp_prep>\n");
 
-       printf("\t\t<database>\n");
+       fprintf(out_file, "\t\t<database>\n");
        fseek(in_file,(rra_start
                       +(rrd.rra_ptr[i].cur_row+1)
                       * rrd.stat_head->ds_cnt
@@ -316,23 +338,27 @@ rrd_dump_r(char *filename)
 #else
 # error "Need strftime"
 #endif
-           printf("\t\t\t<!-- %s / %d --> <row>",somestring,(int)now);
+           fprintf(out_file, "\t\t\t<!-- %s / %d --> <row>",somestring,(int)now);
            for(iii=0;iii<rrd.stat_head->ds_cnt;iii++){                  
                fread(&my_cdp,sizeof(rrd_value_t),1,in_file);           
                if (isnan(my_cdp)){
-                 printf("<v> NaN </v>");
+                 fprintf(out_file, "<v> NaN </v>");
                } else {
-                 printf("<v> %0.10e </v>",my_cdp);
+                 fprintf(out_file, "<v> %0.10e </v>",my_cdp);
                };
            }
-           printf("</row>\n");
+           fprintf(out_file, "</row>\n");
        }
-       printf("\t\t</database>\n\t</rra>\n");
+       fprintf(out_file, "\t\t</database>\n\t</rra>\n");
        
     }
-    printf("</rrd>\n");
+    fprintf(out_file, "</rrd>\n");
     rrd_free(&rrd);
     fclose(in_file);
+    if (out_file != stdout)
+    {
+      fclose(out_file);
+    }
     return(0);
 }
 
index 4b1b96f438e7e2a88a6bdc78edd79037a120fea2..9f46a625df32ca8005566b81474e5f21817ca408 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_error.c   Common Header File
  *****************************************************************************
@@ -80,6 +80,7 @@ rrd_set_error_r(struct rrd_context *rrd_ctx, char *fmt, ...)
     va_start(argp, fmt);
 #ifdef HAVE_VSNPRINTF
     vsnprintf((char *)rrd_ctx->rrd_error, rrd_ctx->len, fmt, argp);
+    rrd_ctx->rrd_error[rrd_ctx->len]='\0';
 #else
     vsprintf((char *)rrd_ctx->rrd_error, fmt, argp);
 #endif
@@ -110,9 +111,8 @@ rrd_new_context(void) {
        (struct rrd_context *) malloc(sizeof(struct rrd_context));
 
     if (rrd_ctx) {
-       rrd_ctx->len = 0;
-       rrd_ctx->rrd_error = malloc(MAXLEN);
-       rrd_ctx->lib_errstr = malloc(ERRBUFLEN);
+       rrd_ctx->rrd_error = malloc(MAXLEN+10);
+       rrd_ctx->lib_errstr = malloc(ERRBUFLEN+10);
        if (rrd_ctx->rrd_error && rrd_ctx->lib_errstr) {
            *rrd_ctx->rrd_error = 0;
            *rrd_ctx->lib_errstr = 0;
index d4c89f9f3c61b23c82077304a8b386097d6181ca..1b85edb1c602080c256b7ab440afbffeee359ab7 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_fetch.c  read date from an rrd to use for further processing
  *****************************************************************************
@@ -53,6 +53,8 @@
  *****************************************************************************/
 
 #include "rrd_tool.h"
+
+#include "rrd_is_thread_safe.h"
 /*#define DEBUG*/
 
 int
@@ -71,10 +73,11 @@ rrd_fetch(int argc,
 
     long     step_tmp =1;
     time_t   start_tmp=0, end_tmp=0;
-    enum     cf_en cf_idx;
+    const char *cf;
 
     struct rrd_time_value start_tv, end_tv;
     char     *parsetime_error = NULL;
+    optind = 0; opterr = 0;  /* initialize getopt */
 
     /* init start and end time */
     parsetime("end-24h", &start_tv);
@@ -147,19 +150,39 @@ rrd_fetch(int argc,
        rrd_set_error("not enough arguments");
        return -1;
     }
-    
-    if ((int)(cf_idx=cf_conv(argv[optind+1])) == -1 ){
-       return -1;
-    }
 
-    if (rrd_fetch_fn(argv[optind],cf_idx,start,end,step,ds_cnt,ds_namv,data) == -1)
+    cf = argv[optind+1];
+
+    if (rrd_fetch_r(argv[optind],cf,start,end,step,ds_cnt,ds_namv,data) == -1)
        return(-1);
     return (0);
 }
 
+int
+rrd_fetch_r(
+    const char           *filename,  /* name of the rrd */
+    const char           *cf,        /* which consolidation function ?*/
+    time_t         *start,
+    time_t         *end,       /* which time frame do you want ?
+                                * will be changed to represent reality */
+    unsigned long  *step,      /* which stepsize do you want? 
+                                * will be changed to represent reality */
+    unsigned long  *ds_cnt,    /* number of data sources in file */
+    char           ***ds_namv, /* names of data_sources */
+    rrd_value_t    **data)     /* two dimensional array containing the data */
+{
+    enum     cf_en cf_idx;
+
+    if ((int)(cf_idx=cf_conv(cf)) == -1 ){
+        return -1;
+    }
+
+    return (rrd_fetch_fn(filename,cf_idx,start,end,step,ds_cnt,ds_namv,data));
+}
+
 int
 rrd_fetch_fn(
-    char           *filename,  /* name of the rrd */
+    const char     *filename,  /* name of the rrd */
     enum cf_en     cf_idx,         /* which consolidation function ?*/
     time_t         *start,
     time_t         *end,       /* which time frame do you want ?
@@ -174,23 +197,26 @@ rrd_fetch_fn(
     FILE           *in_file;
     time_t         cal_start,cal_end, rra_start_time,rra_end_time;
     long  best_full_rra=0, best_part_rra=0, chosen_rra=0, rra_pointer=0;
-    long  best_step_diff=0, tmp_step_diff=0, tmp_match=0, best_match=0;
+    long  best_full_step_diff=0, best_part_step_diff=0, tmp_step_diff=0, tmp_match=0, best_match=0;
     long  full_match, rra_base;
     long           start_offset, end_offset;
     int            first_full = 1;
     int            first_part = 1;
     rrd_t     rrd;
     rrd_value_t    *data_ptr;
-    unsigned long  rows = (*end - *start) / *step;
+    unsigned long  rows;
+    long  rrd_head_size;
 
 #ifdef DEBUG
 fprintf(stderr,"Entered rrd_fetch_fn() searching for the best match\n");
-fprintf(stderr,"Looking for: start %10lu end %10lu step %5lu rows  %lu\n",
-                                               *start,*end,*step,rows);
+fprintf(stderr,"Looking for: start %10lu end %10lu step %5lu\n",
+                                               *start,*end,*step);
 #endif
 
     if(rrd_open(filename,&in_file,&rrd, RRD_READONLY)==-1)
        return(-1);
+
+    rrd_head_size = ftell(in_file);
     
     /* when was the really last update of this file ? */
 
@@ -238,9 +264,9 @@ fprintf(stderr,"Considering: start %10lu end %10lu step %5lu ",
            /* best full match */
            if(cal_end >= *end 
               && cal_start <= *start){
-               if (first_full || (tmp_step_diff < best_step_diff)){
+               if (first_full || (tmp_step_diff < best_full_step_diff)){
                    first_full=0;
-                   best_step_diff = tmp_step_diff;
+                   best_full_step_diff = tmp_step_diff;
                    best_full_rra=i;
 #ifdef DEBUG
 fprintf(stderr,"best full match so far\n");
@@ -261,13 +287,13 @@ fprintf(stderr,"full match, not best\n");
                if (first_part ||
                     (best_match < tmp_match) ||
                     (best_match == tmp_match && 
-                     tmp_step_diff < best_step_diff)){ 
+                     tmp_step_diff < best_part_step_diff)){ 
 #ifdef DEBUG
 fprintf(stderr,"best partial so far\n");
 #endif
                    first_part=0;
                    best_match = tmp_match;
-                   best_step_diff = tmp_step_diff;
+                   best_part_step_diff = tmp_step_diff;
                    best_part_rra =i;
                } else {
 #ifdef DEBUG
@@ -293,8 +319,8 @@ fprintf(stderr,"partial match, not best\n");
     /* set the wish parameters to their real values */
     *step = rrd.stat_head->pdp_step * rrd.rra_def[chosen_rra].pdp_cnt;
     *start -= (*start % *step);
-    if (*end % *step) *end += (*step - *end % *step);
-    rows = (*end - *start) / *step;
+    *end += (*step - *end % *step);
+    rows = (*end - *start) / *step + 1;
 
 #ifdef DEBUG
     fprintf(stderr,"We found:    start %10lu end %10lu step %5lu rows  %lu\n",
@@ -430,6 +456,16 @@ fprintf(stderr,"partial match, not best\n");
                fclose(in_file);
                return(-1);
            }
+#ifdef HAVE_POSIX_FADVISE
+       /* don't pollute the buffer cache with data read from the file. We do this while reading to 
+          keep damage minimal */
+       if (0 != posix_fadvise(fileno(in_file), rrd_head_size, 0, POSIX_FADV_DONTNEED)) {
+           rrd_set_error("setting POSIX_FADV_DONTNEED on '%s': %s",filename, rrd_strerror(errno));
+           fclose(in_file);
+           return(-1);
+       } 
+#endif
+
 #ifdef DEBUG
            fprintf(stderr,"post fetch %li -- ",i);
            for(ii=0;ii<*ds_cnt;ii++)
@@ -444,6 +480,14 @@ fprintf(stderr,"partial match, not best\n");
        
     }
     rrd_free(&rrd);
+#ifdef HAVE_POSIX_FADVISE
+    /* and just to be sure we drop everything except the header at the end */
+    if (0 != posix_fadvise(fileno(in_file), rrd_head_size, 0, POSIX_FADV_DONTNEED)) {
+           rrd_set_error("setting POSIX_FADV_DONTNEED on '%s': %s",filename, rrd_strerror(errno));
+           fclose(in_file);
+           return(-1);
+    } 
+#endif     
     fclose(in_file);
     return(0);
 }
index 0d16a31d3e484645e8b0ab397c3e2f63853c954c..f4e8d4063f2db5709f4116cefb45a1fb3fdd2dbd 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.0.49  Copyright Tobias Oetiker, 1997 - 2005
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_first Return
  *****************************************************************************
@@ -14,6 +14,7 @@ rrd_first(int argc, char **argv)
 {
     int target_rraindex=0;
     char *endptr;
+    optind = 0; opterr = 0;  /* initialize getopt */
 
     while (1){
         static struct option long_options[] =
@@ -67,6 +68,8 @@ rrd_first_r(const char *filename, const int rraindex)
 
     if((rraindex < 0) || (rraindex >= (int)rrd.stat_head->rra_cnt)) {
         rrd_set_error("invalid rraindex number");
+        rrd_free(&rrd);
+        fclose(in_file);
         return(-1);
     }
 
index b9d5c7795eddd0a4d0d087f69bc9a053cda165bf..990f94a915aa3536a37b2d10410ba40e9fc88e98 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1999
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_format.c  RRD Database Format helper functions
  *****************************************************************************
@@ -65,7 +65,7 @@ enum dst_en dst_conv(char *string)
 }
 
 
-enum cf_en cf_conv(char *string)
+enum cf_en cf_conv(const char *string)
 {
 
     converter(AVERAGE,CF_AVERAGE)
index 1a58ebb6f8cf266b652aafff9871494da7c4030f..6f94438ea71c74c7b1dd3a417fc338aeb91c3df3 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.0.33  Copyright Tobias Oetiker, 1997, 1998, 1999
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_format.h  RRD Database Format header
  *****************************************************************************/
diff --git a/src/rrd_getopt.c b/src/rrd_getopt.c
new file mode 100644 (file)
index 0000000..b715ab0
--- /dev/null
@@ -0,0 +1,1002 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97
+   Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.  Its master source is NOT part of
+   the C library, however.  The master source lives in /gd/gnu/lib.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+\f
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+   Ditto for AIX 3.2 and <stdlib.h>.  */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "../rrd_config.h"
+#endif
+
+#if !defined (__STDC__) || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+#include <stdlib.h>
+#include <unistd.h>
+#endif /* GNU C library.  */
+
+#ifdef VMS
+#include <unixlib.h>
+#if HAVE_STRING_H - 0
+#include <string.h>
+#endif
+#endif
+
+#if defined (_WIN32) && !defined (__CYGWIN32__)
+/* It's not Unix, really.  See?  Capital letters.  */
+#include <windows.h>
+#define getpid() GetCurrentProcessId()
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages.
+   When compiling libc, the _ macro is predefined.  */
+#ifdef HAVE_LIBINTL_H
+# include <libintl.h>
+# define _(msgid)      gettext (msgid)
+#else
+# define _(msgid)      (msgid)
+#endif
+#endif
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "rrd_getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* 1003.2 says this must be 1 before any call.  */
+int optind = 1;
+
+/* Formerly, initialization of getopt depended on optind==0, which
+   causes problems with re-calling getopt as programs generally don't
+   know that. */
+
+int __getopt_initialized = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return -1 with `optind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable.  */
+static char *posixly_correct;
+\f
+/* we must include string as there are warnings without it ... */
+#include <string.h>
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+#define        my_index        strchr
+#else
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+       return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+   If not using GCC, it is ok not to declare it.  */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+   That was relevant to code that was here before.  */
+#if !defined (__STDC__) || !__STDC__
+/* gcc with -traditional declares the built-in strlen to return int,
+   and has done so at least since version 2.4.5. -- rms.  */
+extern int strlen (const char *);
+#endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+\f
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+#ifdef _LIBC
+/* Bash 2.0 gives us an environment variable containing flags
+   indicating ARGV elements that should not be considered arguments.  */
+
+static const char *nonoption_flags;
+static int nonoption_flags_len;
+
+static int original_argc;
+static char *const *original_argv;
+
+/* Make sure the environment variable bash 2.0 puts in the environment
+   is valid for the getopt call we must make sure that the ARGV passed
+   to getopt is that one passed to the process.  */
+static void store_args (int argc, char *const *argv) __attribute__ ((unused));
+static void
+store_args (int argc, char *const *argv)
+{
+  /* XXX This is no good solution.  We should rather copy the args so
+     that we can compare them later.  But we must not use malloc(3).  */
+  original_argc = argc;
+  original_argv = argv;
+}
+text_set_element (__libc_subinit, store_args);
+#endif
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+#if defined (__STDC__) && __STDC__
+static void exchange (char **);
+#endif
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int bottom = first_nonopt;
+  int middle = last_nonopt;
+  int top = optind;
+  char *tem;
+
+  /* Exchange the shorter segment with the far end of the longer segment.
+     That puts the shorter segment into the right place.
+     It leaves the longer segment in the right place overall,
+     but it consists of two parts that need to be swapped next.  */
+
+  while (top > middle && middle > bottom)
+    {
+      if (top - middle > middle - bottom)
+       {
+         /* Bottom segment is the short one.  */
+         int len = middle - bottom;
+         register int i;
+
+         /* Swap it with the top part of the top segment.  */
+         for (i = 0; i < len; i++)
+           {
+             tem = argv[bottom + i];
+             argv[bottom + i] = argv[top - (middle - bottom) + i];
+             argv[top - (middle - bottom) + i] = tem;
+           }
+         /* Exclude the moved bottom segment from further swapping.  */
+         top -= len;
+       }
+      else
+       {
+         /* Top segment is the short one.  */
+         int len = top - middle;
+         register int i;
+
+         /* Swap it with the bottom part of the bottom segment.  */
+         for (i = 0; i < len; i++)
+           {
+             tem = argv[bottom + i];
+             argv[bottom + i] = argv[middle + i];
+             argv[middle + i] = tem;
+           }
+         /* Exclude the moved top segment from further swapping.  */
+         bottom += len;
+       }
+    }
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made.  */
+
+#if defined (__STDC__) && __STDC__
+static const char *_getopt_initialize (int, char *const *, const char *);
+#endif
+static const char *
+_getopt_initialize (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  /* Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  first_nonopt = last_nonopt = optind = 1;
+
+  nextchar = NULL;
+
+  posixly_correct = getenv ("POSIXLY_CORRECT");
+
+  /* Determine how to handle the ordering of options and nonoptions.  */
+
+  if (optstring[0] == '-')
+    {
+      ordering = RETURN_IN_ORDER;
+      ++optstring;
+    }
+  else if (optstring[0] == '+')
+    {
+      ordering = REQUIRE_ORDER;
+      ++optstring;
+    }
+  else if (posixly_correct != NULL)
+    ordering = REQUIRE_ORDER;
+  else
+    ordering = PERMUTE;
+
+#ifdef _LIBC
+  if (posixly_correct == NULL
+      && argc == original_argc && argv == original_argv)
+    {
+      /* Bash 2.0 puts a special variable in the environment for each
+        command it runs, specifying which ARGV elements are the results of
+        file name wildcard expansion and therefore should not be
+        considered as options.  */
+      char var[100];
+      sprintf (var, "_%d_GNU_nonoption_argv_flags_", getpid ());
+      nonoption_flags = getenv (var);
+      if (nonoption_flags == NULL)
+       nonoption_flags_len = 0;
+      else
+       nonoption_flags_len = strlen (nonoption_flags);
+    }
+  else
+    nonoption_flags_len = 0;
+#endif
+
+  return optstring;
+}
+\f
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns -1.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  optarg = NULL;
+
+  if (!__getopt_initialized || optind == 0)
+    {
+      optstring = _getopt_initialize (argc, argv, optstring);
+      optind = 1;              /* Don't scan ARGV[0], the program name.  */
+      __getopt_initialized = 1;
+    }
+
+  /* Test whether ARGV[optind] points to a non-option argument.
+     Either it does not have option syntax, or there is an environment flag
+     from the shell indicating it is not an option.  The later information
+     is only used when the used in the GNU libc.  */
+#ifdef _LIBC
+#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0'       \
+                    || (optind < nonoption_flags_len                         \
+                        && nonoption_flags[optind] == '1'))
+#else
+#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#endif
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      /* Advance to the next ARGV-element.  */
+
+      /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+        moved back by the user (who may also have changed the arguments).  */
+      if (last_nonopt > optind)
+       last_nonopt = optind;
+      if (first_nonopt > optind)
+       first_nonopt = optind;
+
+      if (ordering == PERMUTE)
+       {
+         /* If we have just processed some options following some non-options,
+            exchange them so that the options come first.  */
+
+         if (first_nonopt != last_nonopt && last_nonopt != optind)
+           exchange ((char **) argv);
+         else if (last_nonopt != optind)
+           first_nonopt = optind;
+
+         /* Skip any additional non-options
+            and extend the range of non-options previously skipped.  */
+
+         while (optind < argc && NONOPTION_P)
+           optind++;
+         last_nonopt = optind;
+       }
+
+      /* The special ARGV-element `--' means premature end of options.
+        Skip it like a null option,
+        then exchange with previous non-options as if it were an option,
+        then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+       {
+         optind++;
+
+         if (first_nonopt != last_nonopt && last_nonopt != optind)
+           exchange ((char **) argv);
+         else if (first_nonopt == last_nonopt)
+           first_nonopt = optind;
+         last_nonopt = argc;
+
+         optind = argc;
+       }
+
+      /* If we have done all the ARGV-elements, stop the scan
+        and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+       {
+         /* Set the next-arg-index to point at the non-options
+            that we previously skipped, so the caller will digest them.  */
+         if (first_nonopt != last_nonopt)
+           optind = first_nonopt;
+         return -1;
+       }
+
+      /* If we have come to a non-option and did not permute it,
+        either stop the scan or describe it to the caller and pass it by.  */
+
+      if (NONOPTION_P)
+       {
+         if (ordering == REQUIRE_ORDER)
+           return -1;
+         optarg = argv[optind++];
+         return 1;
+       }
+
+      /* We have found another option-ARGV-element.
+        Skip the initial punctuation.  */
+
+      nextchar = (argv[optind] + 1
+                 + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  /* Decode the current option-ARGV-element.  */
+
+  /* Check whether the ARGV-element is a long option.
+
+     If long_only and the ARGV-element has the form "-f", where f is
+     a valid short option, don't consider it an abbreviated form of
+     a long option that starts with f.  Otherwise there would be no
+     way to give the -f short option.
+
+     On the other hand, if there's a long option "fubar" and
+     the ARGV-element is "-fu", do consider that an abbreviation of
+     the long option, just like "--fu", and not "-f" with arg "u".
+
+     This distinction seems to be the most useful approach.  */
+
+  if (longopts != NULL
+      && (argv[optind][1] == '-'
+         || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+    {
+      char *nameend;
+      const struct option *p;
+      const struct option *pfound = NULL;
+      int exact = 0;
+      int ambig = 0;
+      int indfound = -1;
+      int option_index;
+
+      for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+       /* Do nothing.  */ ;
+
+      /* Test all long options for either exact match
+        or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name; p++, option_index++)
+       if (!strncmp (p->name, nextchar, nameend - nextchar))
+         {
+           if ((unsigned int) (nameend - nextchar)
+               == (unsigned int) strlen (p->name))
+             {
+               /* Exact match found.  */
+               pfound = p;
+               indfound = option_index;
+               exact = 1;
+               break;
+             }
+           else if (pfound == NULL)
+             {
+               /* First nonexact match found.  */
+               pfound = p;
+               indfound = option_index;
+             }
+           else
+             /* Second or later nonexact match found.  */
+             ambig = 1;
+         }
+
+      if (ambig && !exact)
+       {
+         if (opterr)
+           fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
+                    argv[0], argv[optind]);
+         nextchar += strlen (nextchar);
+         optind++;
+         optopt = 0;
+         return '?';
+       }
+
+      if (pfound != NULL)
+       {
+         option_index = indfound;
+         optind++;
+         if (*nameend)
+           {
+             /* Don't test has_arg with >, because some C compilers don't
+                allow it to be used on enums.  */
+             if (pfound->has_arg)
+               optarg = nameend + 1;
+             else
+               {
+                 if (opterr) {
+                  if (argv[optind - 1][1] == '-')
+                   /* --option */
+                   fprintf (stderr,
+                    _("%s: option `--%s' doesn't allow an argument\n"),
+                    argv[0], pfound->name);
+                  else
+                   /* +option or -option */
+                   fprintf (stderr,
+                    _("%s: option `%c%s' doesn't allow an argument\n"),
+                    argv[0], argv[optind - 1][0], pfound->name);
+                 }
+                 nextchar += strlen (nextchar);
+
+                 optopt = pfound->val;
+                 return '?';
+               }
+           }
+         else if (pfound->has_arg == 1)
+           {
+             if (optind < argc)
+               optarg = argv[optind++];
+             else
+               {
+                 if (opterr)
+                   fprintf (stderr,
+                          _("%s: option `%s' requires an argument\n"),
+                          argv[0], argv[optind - 1]);
+                 nextchar += strlen (nextchar);
+                 optopt = pfound->val;
+                 return optstring[0] == ':' ? ':' : '?';
+               }
+           }
+         nextchar += strlen (nextchar);
+         if (longind != NULL)
+           *longind = option_index;
+         if (pfound->flag)
+           {
+             *(pfound->flag) = pfound->val;
+             return 0;
+           }
+         return pfound->val;
+       }
+
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+        or the option starts with '--' or is not a valid short
+        option, then it's an error.
+        Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+         || my_index (optstring, *nextchar) == NULL)
+       {
+         if (opterr)
+           {
+             if (argv[optind][1] == '-')
+               /* --option */
+               fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
+                        argv[0], nextchar);
+             else
+               /* +option or -option */
+               fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
+                        argv[0], argv[optind][0], nextchar);
+           }
+         nextchar = (char *) "";
+         optind++;
+         optopt = 0;
+         return '?';
+       }
+    }
+
+  /* Look at and handle the next short option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+       if (opterr)
+         {
+           if (posixly_correct)
+             /* 1003.2 specifies the format of this message.  */
+             fprintf (stderr, _("%s: illegal option -- %c\n"),
+                      argv[0], c);
+           else
+             fprintf (stderr, _("%s: invalid option -- %c\n"),
+                      argv[0], c);
+         }
+       optopt = c;
+       return '?';
+      }
+    /* Convenience. Treat POSIX -W foo same as long option --foo */
+    if (temp[0] == 'W' && temp[1] == ';')
+      {
+       char *nameend;
+       const struct option *p;
+       const struct option *pfound = NULL;
+       int exact = 0;
+       int ambig = 0;
+       int indfound = 0;
+       int option_index;
+
+       /* This is an option that requires an argument.  */
+       if (*nextchar != '\0')
+         {
+           optarg = nextchar;
+           /* If we end this ARGV-element by taking the rest as an arg,
+              we must advance to the next element now.  */
+           optind++;
+         }
+       else if (optind == argc)
+         {
+           if (opterr)
+             {
+               /* 1003.2 specifies the format of this message.  */
+               fprintf (stderr, _("%s: option requires an argument -- %c\n"),
+                        argv[0], c);
+             }
+           optopt = c;
+           if (optstring[0] == ':')
+             c = ':';
+           else
+             c = '?';
+           return c;
+         }
+       else
+         /* We already incremented `optind' once;
+            increment it again when taking next ARGV-elt as argument.  */
+         optarg = argv[optind++];
+
+       /* optarg is now the argument, see if it's in the
+          table of longopts.  */
+
+       for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
+         /* Do nothing.  */ ;
+
+       /* Test all long options for either exact match
+          or abbreviated matches.  */
+       for (p = longopts, option_index = 0; p->name; p++, option_index++)
+         if (!strncmp (p->name, nextchar, nameend - nextchar))
+           {
+             if ((unsigned int) (nameend - nextchar) == strlen (p->name))
+               {
+                 /* Exact match found.  */
+                 pfound = p;
+                 indfound = option_index;
+                 exact = 1;
+                 break;
+               }
+             else if (pfound == NULL)
+               {
+                 /* First nonexact match found.  */
+                 pfound = p;
+                 indfound = option_index;
+               }
+             else
+               /* Second or later nonexact match found.  */
+               ambig = 1;
+           }
+       if (ambig && !exact)
+         {
+           if (opterr)
+             fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
+                      argv[0], argv[optind]);
+           nextchar += strlen (nextchar);
+           optind++;
+           return '?';
+         }
+       if (pfound != NULL)
+         {
+           option_index = indfound;
+           if (*nameend)
+             {
+               /* Don't test has_arg with >, because some C compilers don't
+                  allow it to be used on enums.  */
+               if (pfound->has_arg)
+                 optarg = nameend + 1;
+               else
+                 {
+                   if (opterr)
+                     fprintf (stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+                              argv[0], pfound->name);
+
+                   nextchar += strlen (nextchar);
+                   return '?';
+                 }
+             }
+           else if (pfound->has_arg == 1)
+             {
+               if (optind < argc)
+                 optarg = argv[optind++];
+               else
+                 {
+                   if (opterr)
+                     fprintf (stderr,
+                              _("%s: option `%s' requires an argument\n"),
+                              argv[0], argv[optind - 1]);
+                   nextchar += strlen (nextchar);
+                   return optstring[0] == ':' ? ':' : '?';
+                 }
+             }
+           nextchar += strlen (nextchar);
+           if (longind != NULL)
+             *longind = option_index;
+           if (pfound->flag)
+             {
+               *(pfound->flag) = pfound->val;
+               return 0;
+             }
+           return pfound->val;
+         }
+         nextchar = NULL;
+         return 'W';   /* Let the application handle it.   */
+      }
+    if (temp[1] == ':')
+      {
+       if (temp[2] == ':')
+         {
+           /* This is an option that accepts an argument optionally.  */
+           if (*nextchar != '\0')
+             {
+               optarg = nextchar;
+               optind++;
+             }
+           else
+             optarg = NULL;
+           nextchar = NULL;
+         }
+       else
+         {
+           /* This is an option that requires an argument.  */
+           if (*nextchar != '\0')
+             {
+               optarg = nextchar;
+               /* If we end this ARGV-element by taking the rest as an arg,
+                  we must advance to the next element now.  */
+               optind++;
+             }
+           else if (optind == argc)
+             {
+               if (opterr)
+                 {
+                   /* 1003.2 specifies the format of this message.  */
+                   fprintf (stderr,
+                          _("%s: option requires an argument -- %c\n"),
+                          argv[0], c);
+                 }
+               optopt = c;
+               if (optstring[0] == ':')
+                 c = ':';
+               else
+                 c = '?';
+             }
+           else
+             /* We already incremented `optind' once;
+                increment it again when taking next ARGV-elt as argument.  */
+             optarg = argv[optind++];
+           nextchar = NULL;
+         }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+                          (const struct option *) 0,
+                          (int *) 0,
+                          0);
+}
+
+#endif /* Not ELIDE_CODE.  */
+\f
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+
+      c = getopt (argc, argv, "abc:d:0123456789");
+      if (c == -1)
+       break;
+
+      switch (c)
+       {
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+         if (digit_optind != 0 && digit_optind != this_option_optind)
+           printf ("digits occur in two different argv-elements.\n");
+         digit_optind = this_option_optind;
+         printf ("option %c\n", c);
+         break;
+
+       case 'a':
+         printf ("option a\n");
+         break;
+
+       case 'b':
+         printf ("option b\n");
+         break;
+
+       case 'c':
+         printf ("option c with value `%s'\n", optarg);
+         break;
+
+       case '?':
+         break;
+
+       default:
+         printf ("?? getopt returned character code 0%o ??\n", c);
+       }
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+       printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/src/rrd_getopt.h b/src/rrd_getopt.h
new file mode 100644 (file)
index 0000000..7dad11b
--- /dev/null
@@ -0,0 +1,133 @@
+/* Declarations for getopt.
+   Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.  Its master source is NOT part of
+   the C library, however.  The master source lives in /gd/gnu/lib.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument         (or 0) if the option does not take an argument,
+   required_argument   (or 1) if the option requires an argument,
+   optional_argument   (or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+struct option
+{
+#if defined (__STDC__) && __STDC__
+  const char *name;
+#else
+  char *name;
+#endif
+  /* has_arg can't be an enum because some compilers complain about
+     type mismatches in all the code that assumes it is an int.  */
+  int has_arg;
+  int *flag;
+  int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+#define        no_argument             0
+#define required_argument      1
+#define optional_argument      2
+
+#if defined (__STDC__) && __STDC__
+#ifdef __GNU_LIBRARY__
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+                       const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+                            const char *shortopts,
+                            const struct option *longopts, int *longind);
+
+/* Internal only.  Users should not call this directly.  */
+extern int _getopt_internal (int argc, char *const *argv,
+                            const char *shortopts,
+                            const struct option *longopts, int *longind,
+                            int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/src/rrd_getopt1.c b/src/rrd_getopt1.c
new file mode 100644 (file)
index 0000000..14e1e88
--- /dev/null
@@ -0,0 +1,189 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+   Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.  Its master source is NOT part of
+   the C library, however.  The master source lives in /gd/gnu/lib.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+\f
+#ifdef HAVE_CONFIG_H
+#include "../rrd_config.h"
+#endif
+
+#include "rrd_getopt.h"
+
+#if !defined (__STDC__) || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#endif
+
+#ifndef        NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead.  */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* Not ELIDE_CODE.  */
+\f
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+      int option_index = 0;
+      static struct option long_options[] =
+      {
+       {"add", 1, 0, 0},
+       {"append", 0, 0, 0},
+       {"delete", 1, 0, 0},
+       {"verbose", 0, 0, 0},
+       {"create", 0, 0, 0},
+       {"file", 1, 0, 0},
+       {0, 0, 0, 0}
+      };
+
+      c = getopt_long (argc, argv, "abc:d:0123456789",
+                      long_options, &option_index);
+      if (c == -1)
+       break;
+
+      switch (c)
+       {
+       case 0:
+         printf ("option %s", long_options[option_index].name);
+         if (optarg)
+           printf (" with arg %s", optarg);
+         printf ("\n");
+         break;
+
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+         if (digit_optind != 0 && digit_optind != this_option_optind)
+           printf ("digits occur in two different argv-elements.\n");
+         digit_optind = this_option_optind;
+         printf ("option %c\n", c);
+         break;
+
+       case 'a':
+         printf ("option a\n");
+         break;
+
+       case 'b':
+         printf ("option b\n");
+         break;
+
+       case 'c':
+         printf ("option c with value `%s'\n", optarg);
+         break;
+
+       case 'd':
+         printf ("option d with value `%s'\n", optarg);
+         break;
+
+       case '?':
+         break;
+
+       default:
+         printf ("?? getopt returned character code 0%o ??\n", c);
+       }
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+       printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
index 49b93685e7cc9931e3332d51281b8605570f311f..2cdf20cced85184bb8aee394694b9aed3be5d9cf 100644 (file)
@@ -1,16 +1,21 @@
 /****************************************************************************
- * RRDtool 1.2.x  Copyright Tobias Oetiker, 1997 - 2005
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  ****************************************************************************
  * rrd_gfx.c  graphics wrapper for rrdtool
   **************************************************************************/
 
 /* #define DEBUG */
 
-#ifdef DEBUG
-# define DPRINT(x)    (void)(printf x, printf("\n"))
-#else
-# define DPRINT(x)
-#endif
+/* stupid MSVC doesnt support variadic macros = no debug for now! */
+#ifdef _MSC_VER
+# define RRDPRINTF()
+#else 
+# ifdef DEBUG
+#  define RRDPRINTF(...)  fprintf(stderr, __VA_ARGS__);
+# else
+#  define RRDPRINTF(...)
+# endif /* DEBUG */
+#endif /* _MSC_VER */
 #include "rrd_tool.h"
 #include <png.h>
 #include <ft2build.h>
 
 #include "rrd_gfx.h"
 #include "rrd_afm.h"
+#include "unused.h"
 
 /* lines are better drawn on the pixle than between pixles */
 #define LINEOFFSET 0.5
 
+#define USE_PDF_FAKE_ALPHA 1
+#define USE_EPS_FAKE_ALPHA 1
+
 typedef struct gfx_char_s *gfx_char;
 struct gfx_char_s {
   FT_UInt     index;    /* glyph index */
@@ -34,7 +43,7 @@ typedef struct gfx_string_s *gfx_string;
 struct gfx_string_s {
   unsigned int    width;
   unsigned int    height;
-  size_t          count;  /* number of characters */
+  int            count;  /* number of characters */
   gfx_char        glyphs;
   size_t          num_glyphs;
   FT_BBox         bbox;
@@ -45,8 +54,8 @@ struct gfx_string_s {
 static void compute_string_bbox(gfx_string string);
 
 /* create a freetype glyph string */
-gfx_string gfx_string_create ( FT_Face face,
-                               const char *text, int rotation, double tabwidth);
+gfx_string gfx_string_create ( gfx_canvas_t *canvas, FT_Face face,
+                               const char *text, int rotation, double tabwidth, double size);
 
 /* create a freetype glyph string */
 static void gfx_string_destroy ( gfx_string string );
@@ -62,7 +71,6 @@ gfx_node_t *gfx_new_node( gfx_canvas_t *canvas,enum gfx_en type){
   node->points = 0;
   node->points_max =0;
   node->closed_path = 0;
-  node->svp = NULL;         /* svp */
   node->filename = NULL;             /* font or image filename */
   node->text = NULL;
   node->x = 0.0;
@@ -89,7 +97,9 @@ gfx_canvas_t *gfx_new_canvas (void) {
     canvas->imgformat = IF_PNG; /* we default to PNG output */
     canvas->interlaced = 0;
     canvas->zoom = 1.0;
-    return canvas;    
+    canvas->font_aa_threshold = -1.0;
+    canvas->aa_type = AA_NORMAL;
+    return canvas;
 }
 
 /* create a new line */
@@ -114,7 +124,7 @@ gfx_node_t  *gfx_new_dashed_line(gfx_canvas_t *canvas,
   if (vec == NULL) return NULL;
   vec[0].code = ART_MOVETO_OPEN; vec[0].x=X0+LINEOFFSET; vec[0].y=Y0+LINEOFFSET;
   vec[1].code = ART_LINETO; vec[1].x=X1+LINEOFFSET; vec[1].y=Y1+LINEOFFSET;
-  vec[2].code = ART_END;
+  vec[2].code = ART_END; vec[2].x=0;vec[2].y=0;
   
   node->points = 3;
   node->points_max = 3;
@@ -143,7 +153,7 @@ gfx_node_t   *gfx_new_area   (gfx_canvas_t *canvas,
   vec[1].code = ART_LINETO; vec[1].x=X1; vec[1].y=Y1;
   vec[2].code = ART_LINETO; vec[2].x=X2; vec[2].y=Y2;
   vec[3].code = ART_LINETO; vec[3].x=X0; vec[3].y=Y0;
-  vec[4].code = ART_END;
+  vec[4].code = ART_END; vec[4].x=0; vec[4].y=0;
   
   node->points = 5;
   node->points_max = 5;
@@ -211,10 +221,6 @@ gfx_node_t   *gfx_new_text   (gfx_canvas_t *canvas,
                              enum gfx_v_align_en v_align,
                               char* text){
    gfx_node_t *node = gfx_new_node(canvas,GFX_TEXT);
-/*   if (angle != 0.0){*/
-       /* currently we only support 0 and 270 */
-/*       angle = 270.0;
-   }*/
    
    node->text = strdup(text);
    node->size = size;
@@ -280,7 +286,7 @@ double gfx_get_text_width ( gfx_canvas_t *canvas,
                            double tabwidth, char* text, int rotation){
   switch (canvas->imgformat) {
   case IF_PNG: 
-    return gfx_get_text_width_libart (start, font, size, tabwidth, text, rotation);
+    return gfx_get_text_width_libart (canvas, start, font, size, tabwidth, text, rotation);
   case IF_SVG: /* fall through */ 
   case IF_EPS:
   case IF_PDF:
@@ -291,8 +297,8 @@ double gfx_get_text_width ( gfx_canvas_t *canvas,
 }
 
 double gfx_get_text_width_libart (
-                           double start, char* font, double size,
-                           double tabwidth, char* text, int rotation){
+                           gfx_canvas_t *canvas, double UNUSED(start), char* font, double size,
+                           double tabwidth, char* text, int rotation ){
 
   int           error;
   double        text_width=0;
@@ -302,11 +308,16 @@ double gfx_get_text_width_libart (
 
   FT_Init_FreeType( &library );
   error = FT_New_Face( library, font, 0, &face );
-  if ( error ) return -1;
+  if ( error ) {
+    FT_Done_FreeType(library);
+    return -1;
+  }
   error = FT_Set_Char_Size(face,  size*64,size*64,  100,100);
-  if ( error ) return -1;
-
-  string = gfx_string_create( face, text, rotation,tabwidth);
+  if ( error ) {
+    FT_Done_FreeType(library);
+    return -1;
+  }
+  string = gfx_string_create( canvas, face, text, rotation, tabwidth, size );
   text_width = string->width;
   gfx_string_destroy(string);
   FT_Done_FreeType(library);
@@ -325,14 +336,6 @@ static void gfx_libart_close_path(gfx_node_t *node, ArtVpath **vec)
     art_vpath_add_point (vec, &points, &points_max, ART_END, 0, 0);
 }
 
-static void gfx_round_scaled_coordinates(ArtVpath *vec)
-{
-    while (vec->code != ART_END) {
-       vec->x = floor(vec->x - LINEOFFSET + 0.5) + LINEOFFSET;
-       vec->y = floor(vec->y - LINEOFFSET + 0.5) + LINEOFFSET;
-       vec++;
-    }
-}
 
 /* find bbox of a string */
 static void compute_string_bbox(gfx_string string) {
@@ -371,8 +374,8 @@ static void compute_string_bbox(gfx_string string) {
 } 
 
 /* create a free type glyph string */
-gfx_string gfx_string_create(FT_Face face,const char *text,
-        int rotation, double tabwidth)
+gfx_string gfx_string_create(gfx_canvas_t *canvas, FT_Face face,const char *text,
+        int rotation, double tabwidth, double size )
 {
 
   FT_GlyphSlot  slot = face->glyph;  /* a small shortcut */
@@ -380,19 +383,36 @@ gfx_string gfx_string_create(FT_Face face,const char *text,
   FT_UInt       previous;
   FT_Vector     ft_pen;
 
-  gfx_string    string;
+  gfx_string    string = (gfx_string) malloc (sizeof(struct gfx_string_s));
+
   gfx_char      glyph;          /* current glyph in table */
-  unsigned int  n;
+  int          n;
   int           error;
-  int        gottab;    
+  int        gottab = 0;    
+
+#ifdef HAVE_MBSTOWCS
+  wchar_t      *cstr;
+  size_t       clen = strlen(text)+1;
+  cstr = malloc(sizeof(wchar_t) * clen); /* yes we are allocating probably too much here, I know */
+  string->count=mbstowcs(cstr,text,clen);
+  if ( string->count == -1){
+  /* conversion did not work, so lets fall back to just use what we got */
+       string->count=clen-1;
+        for(n=0;text[n] != '\0';n++){
+            cstr[n]=(unsigned char)text[n];
+        }
+  }
+#else
+  char         *cstr = strdup(text);
+  string->count = strlen (text);
+#endif
 
   ft_pen.x = 0;   /* start at (0,0) !! */
   ft_pen.y = 0;
 
-  string = (gfx_string) malloc (sizeof(struct gfx_string_s));
+
   string->width = 0;
   string->height = 0;
-  string->count = strlen (text);
   string->glyphs = (gfx_char) calloc (string->count,sizeof(struct gfx_char_s));
   string->num_glyphs = 0;
   string->transform.xx = (FT_Fixed)( cos(M_PI*(rotation)/180.0)*0x10000);
@@ -403,14 +423,16 @@ gfx_string gfx_string_create(FT_Face face,const char *text,
   use_kerning = FT_HAS_KERNING(face);
   previous    = 0;
   glyph = string->glyphs;
-  for (n=0; n<string->count; n++, glyph++) {
+  for (n=0; n<string->count;glyph++,n++) {
     FT_Vector   vec;
     /* handle the tabs ...
        have a witespace glyph inserted, but set its width such that the distance
     of the new right edge is x times tabwidth from 0,0 where x is an integer. */    
-    char letter = text[n];
+    unsigned int letter = cstr[n];
+       letter = afm_fix_osx_charset(letter); /* unsafe macro */
+          
     gottab = 0;
-    if (letter == '\\' && n+1 < string->count && text[n+1] == 't'){
+    if (letter == '\\' && n+1 < string->count && cstr[n+1] == 't'){
             /* we have a tab here so skip the backslash and
                set t to ' ' so that we get a white space */
             gottab = 1;
@@ -426,7 +448,6 @@ gfx_string gfx_string_create(FT_Face face,const char *text,
     glyph->pos.x = 0;
     glyph->pos.y = 0;
     glyph->image = NULL;
-
     glyph->index = FT_Get_Char_Index( face, letter );
 
     /* compute glyph origin */
@@ -440,14 +461,17 @@ gfx_string gfx_string_create(FT_Face face,const char *text,
 
     /* load the glyph image (in its native format) */
     /* for now, we take a monochrome glyph bitmap */
-    error = FT_Load_Glyph (face, glyph->index, FT_LOAD_DEFAULT);
+    error = FT_Load_Glyph (face, glyph->index, size > canvas->font_aa_threshold ?
+                            canvas->aa_type == AA_NORMAL ? FT_LOAD_TARGET_NORMAL :
+                            canvas->aa_type == AA_LIGHT ? FT_LOAD_TARGET_LIGHT :
+                            FT_LOAD_TARGET_MONO : FT_LOAD_TARGET_MONO);
     if (error) {
-      fprintf (stderr, "couldn't load glyph:  %c\n", letter);
+      RRDPRINTF("couldn't load glyph:  %c\n", letter)
       continue;
     }
     error = FT_Get_Glyph (slot, &glyph->image);
     if (error) {
-      fprintf (stderr, "couldn't get glyph from slot:  %c\n", letter);
+      RRDPRINTF("couldn't get glyph %c from slot %d\n", letter, (int)slot)
       continue;
     }
     /* if we are in tabbing mode, we replace the tab with a space and shift the position
@@ -469,14 +493,17 @@ gfx_string gfx_string_create(FT_Face face,const char *text,
     FT_Vector_Transform (&vec, &string->transform);
     error = FT_Glyph_Transform (glyph->image, &string->transform, &vec);
     if (error) {
-      fprintf (stderr, "couldn't transform glyph\n");
+      RRDPRINTF("couldn't transform glyph id %d\n", letter)
       continue;
     }
 
     /* convert to a bitmap - destroy native image */
-    error = FT_Glyph_To_Bitmap (&glyph->image, FT_RENDER_MODE_NORMAL, 0, 1);
+    error = FT_Glyph_To_Bitmap (&glyph->image, size > canvas->font_aa_threshold ?
+                            canvas->aa_type == AA_NORMAL ? FT_RENDER_MODE_NORMAL :
+                            canvas->aa_type == AA_LIGHT ? FT_RENDER_MODE_LIGHT :
+                            FT_RENDER_MODE_MONO : FT_RENDER_MODE_MONO, 0, 1);
     if (error) {
-      fprintf (stderr, "couldn't convert glyph to bitmap\n");
+      RRDPRINTF("couldn't convert glyph id %d to bitmap\n", letter)
       continue;
     }
 
@@ -484,14 +511,15 @@ gfx_string gfx_string_create(FT_Face face,const char *text,
     previous = glyph->index;
     string->num_glyphs++;
   }
+  free(cstr);
 /*  printf ("number of glyphs = %d\n", string->num_glyphs);*/
   compute_string_bbox( string );
   /* the last character was a tab */  
-  if (gottab) {
+  /* if (gottab) { */
       string->width = ft_pen.x;
-  } else {
+  /* } else {
       string->width = string->bbox.xMax - string->bbox.xMin;
-  }
+  } */
   string->height = string->bbox.yMax - string->bbox.yMin;
   return string;
 }
@@ -508,14 +536,23 @@ int           gfx_render_png (gfx_canvas_t *canvas,
     
     FT_Library    library;
     gfx_node_t *node = canvas->firstnode;    
+    /*
     art_u8 red = background >> 24, green = (background >> 16) & 0xff;
     art_u8 blue = (background >> 8) & 0xff, alpha = ( background & 0xff );
+    */
     unsigned long pys_width = width * canvas->zoom;
     unsigned long pys_height = height * canvas->zoom;
-    const int bytes_per_pixel = 3;
+    const int bytes_per_pixel = 4;
     unsigned long rowstride = pys_width*bytes_per_pixel; /* bytes per pixel */
-    art_u8 *buffer = art_new (art_u8, rowstride*pys_height);
-    art_rgb_run_alpha (buffer, red, green, blue, alpha, pys_width*pys_height);
+    
+    /* fill that buffer with out background color */
+    gfx_color_t *buffp = art_new (gfx_color_t, pys_width*pys_height);
+    art_u8 *buffer = (art_u8 *)buffp;
+    unsigned long i;
+    for (i=0;i<pys_width*pys_height;
+        i++){
+       *(buffp++)=background;
+    }
     FT_Init_FreeType( &library );
     while(node){
         switch (node->type) {
@@ -528,24 +565,34 @@ int           gfx_render_png (gfx_canvas_t *canvas,
             vec = art_vpath_affine_transform(node->path,dst);
            if (node->closed_path)
                gfx_libart_close_path(node, &vec);
-           gfx_round_scaled_coordinates(vec);
+           /* gfx_round_scaled_coordinates(vec); */
+            /* pvec = art_vpath_perturb(vec);
+              art_free(vec); */
             if(node->type == GFX_LINE){
                 svp = art_svp_vpath_stroke ( vec, ART_PATH_STROKE_JOIN_ROUND,
                                              ART_PATH_STROKE_CAP_ROUND,
-                                             node->size*canvas->zoom,1,1);
+                                             node->size*canvas->zoom,4,0.25);
             } else {
-                svp = art_svp_from_vpath ( vec );
+                svp  = art_svp_from_vpath ( vec );
+               /* this takes time and is unnecessary since we make
+                  sure elsewhere that the areas are going clock-whise */
+               /*  svpt = art_svp_uncross( svp );
+                    art_svp_free(svp);
+                   svp  = art_svp_rewind_uncrossed(svpt,ART_WIND_RULE_NONZERO); 
+                    art_svp_free(svpt);
+                 */
             }
             art_free(vec);
-            art_rgb_svp_alpha (svp ,0,0, pys_width, pys_height,
-                               node->color, buffer, rowstride, NULL);
-            art_free(svp);
+           /* this is from gnome since libart does not have this yet */
+            gnome_print_art_rgba_svp_alpha (svp ,0,0, pys_width, pys_height,
+                                node->color, buffer, rowstride, NULL);
+            art_svp_free(svp);
             break;
         }
         case GFX_TEXT: {
             unsigned int  n;
             int  error;
-            art_u8 fcolor[3],falpha;
+            art_u8 fcolor[4],falpha;
             FT_Face       face;
             gfx_char      glyph;
             gfx_string    string;
@@ -553,7 +600,7 @@ int           gfx_render_png (gfx_canvas_t *canvas,
 
             float pen_x = 0.0 , pen_y = 0.0;
             /* double x,y; */
-            long   ix,iy,iz;
+            long   ix,iy;
             
             fcolor[0] = node->color >> 24;
             fcolor[1] = (node->color >> 16) & 0xff;
@@ -563,18 +610,26 @@ int           gfx_render_png (gfx_canvas_t *canvas,
                                  (char *)node->filename,
                                  0,
                                  &face );
-           if ( error ) break;
-
+           if ( error ) {
+               rrd_set_error("failed to load %s",node->filename);
+               
+               break;
+           }
             error = FT_Set_Char_Size(face,   /* handle to face object            */
                                      (long)(node->size*64),
                                      (long)(node->size*64),
                                      (long)(100*canvas->zoom),
                                      (long)(100*canvas->zoom));
-            if ( error ) break;
+            if ( error ) {
+                FT_Done_Face(face);
+                break;
+            }
             pen_x = node->x * canvas->zoom;
             pen_y = node->y * canvas->zoom;
 
-            string = gfx_string_create (face, node->text, node->angle, node->tabwidth);
+            string = gfx_string_create (canvas, face, node->text, node->angle, node->tabwidth, node->size);
+            FT_Done_Face(face);
+
             switch(node->halign){
             case GFX_H_RIGHT:  vec.x = -string->bbox.xMax;
                                break;          
@@ -601,19 +656,19 @@ int           gfx_render_png (gfx_canvas_t *canvas,
            pen_x += vec.x/64;
            pen_y += vec.y/64;
             glyph = string->glyphs;
-            for(n=0; n<string->num_glyphs; ++n, ++glyph) {
+            for(n=0; n<string->num_glyphs; n++, glyph++) {
                 int gr;
                 FT_Glyph        image;
                 FT_BitmapGlyph  bit;
-
+               /* long buf_x,comp_n; */
                /* make copy to transform */
                 if (! glyph->image) {
-                  fprintf (stderr, "no image\n");
+                  RRDPRINTF("no image\n")
                   continue;
                 }
                 error = FT_Glyph_Copy (glyph->image, &image);
                 if (error) {
-                  fprintf (stderr, "couldn't copy image\n");
+                  RRDPRINTF("couldn't copy image\n")
                   continue;
                 }
 
@@ -622,9 +677,67 @@ int           gfx_render_png (gfx_canvas_t *canvas,
                 FT_Vector_Transform (&vec, &string->transform);
 
                 bit = (FT_BitmapGlyph) image;
-
                 gr = bit->bitmap.num_grays -1;
-                for (iy=0; iy < bit->bitmap.rows; iy++){
+/* 
+               buf_x = (pen_x + 0.5) + (double)bit->left;
+               comp_n = buf_x + bit->bitmap.width > pys_width ? pys_width - buf_x : bit->bitmap.width;
+                if (buf_x < 0 || buf_x >= (long)pys_width) continue;
+               buf_x *=  bytes_per_pixel ;
+               for (iy=0; iy < bit->bitmap.rows; iy++){                    
+                   long buf_y = iy+(pen_y+0.5)-(double)bit->top;
+                   if (buf_y < 0 || buf_y >= (long)pys_height) continue;
+                    buf_y *= rowstride;
+                   for (ix=0;ix < bit->bitmap.width;ix++){             
+                       *(letter + (ix*bytes_per_pixel+3)) = *(bit->bitmap.buffer + iy * bit->bitmap.width + ix);
+                   }
+                   art_rgba_rgba_composite(buffer + buf_y + buf_x ,letter,comp_n);
+                }
+                art_free(letter);
+*/
+                switch ( bit->bitmap.pixel_mode ) {
+                    case FT_PIXEL_MODE_GRAY:
+                        for (iy=0; iy < bit->bitmap.rows; iy++){
+                            long buf_y = iy+(pen_y+0.5)-bit->top;
+                            if (buf_y < 0 || buf_y >= (long)pys_height) continue;
+                            buf_y *= rowstride;
+                            for (ix=0;ix < bit->bitmap.width;ix++){
+                                long buf_x = ix + (pen_x + 0.5) + (double)bit->left ;
+                                art_u8 font_alpha;
+
+                                if (buf_x < 0 || buf_x >= (long)pys_width) continue;
+                                buf_x *=  bytes_per_pixel ;
+                                font_alpha =  *(bit->bitmap.buffer + iy * bit->bitmap.pitch + ix);
+                    if (font_alpha > 0){
+                                    fcolor[3] =  (art_u8)((double)font_alpha / gr * falpha);
+                        art_rgba_rgba_composite(buffer + buf_y + buf_x ,fcolor,1);
+                                }
+                            }
+                        }
+                        break;
+
+                    case FT_PIXEL_MODE_MONO:
+                        for (iy=0; iy < bit->bitmap.rows; iy++){
+                            long buf_y = iy+(pen_y+0.5)-bit->top;
+                            if (buf_y < 0 || buf_y >= (long)pys_height) continue;
+                            buf_y *= rowstride;
+                            for (ix=0;ix < bit->bitmap.width;ix++){
+                                long buf_x = ix + (pen_x + 0.5) + (double)bit->left ;
+
+                                if (buf_x < 0 || buf_x >= (long)pys_width) continue;
+                                buf_x *=  bytes_per_pixel ;
+                                if ( (fcolor[3] = falpha * ((*(bit->bitmap.buffer + iy * bit->bitmap.pitch + ix/8) >> (7 - (ix % 8))) & 1)) > 0 )
+                                    art_rgba_rgba_composite(buffer + buf_y + buf_x ,fcolor,1);
+                            }
+                        }
+                        break;
+
+                        default:
+                            rrd_set_error("unknown freetype pixel mode: %d", bit->bitmap.pixel_mode);
+                            break;
+                }
+
+/*
+                for (iy=0; iy < bit->bitmap.rows; iy++){                   
                     long buf_y = iy+(pen_y+0.5)-bit->top;
                     if (buf_y < 0 || buf_y >= (long)pys_height) continue;
                     buf_y *= rowstride;
@@ -643,6 +756,7 @@ int           gfx_render_png (gfx_canvas_t *canvas,
                         }
                     }
                 }
+*/
                 FT_Done_Glyph (image);
             }
             gfx_string_destroy(string);
@@ -664,12 +778,12 @@ gfx_destroy    (gfx_canvas_t *canvas){
   while(node){
     next = node->next;
     art_free(node->path);
-    art_free(node->svp);
     free(node->text);
     free(node->filename);
     art_free(node);
     node = next;
   }
+  art_free(canvas);
   return 0;
 }
  
@@ -696,6 +810,7 @@ static int gfx_save_png (art_u8 *buffer, FILE *fp,  long width, long height, lon
 
   if (info_ptr == NULL)
     {
+      png_free(png_ptr,row_pointers);
       png_destroy_write_struct(&png_ptr,  (png_infopp)NULL);
       return (1);
     }
@@ -709,7 +824,7 @@ static int gfx_save_png (art_u8 *buffer, FILE *fp,  long width, long height, lon
 
   png_init_io(png_ptr, fp);
   png_set_IHDR (png_ptr, info_ptr,width, height,
-                8, PNG_COLOR_TYPE_RGB,
+                8, PNG_COLOR_TYPE_RGB_ALPHA,
                 PNG_INTERLACE_NONE,
                 PNG_COMPRESSION_TYPE_DEFAULT,
                 PNG_FILTER_TYPE_DEFAULT);
@@ -719,9 +834,11 @@ static int gfx_save_png (art_u8 *buffer, FILE *fp,  long width, long height, lon
   text[0].compression = PNG_TEXT_COMPRESSION_NONE;
   png_set_text (png_ptr, info_ptr, text, 1);
 
-  /* lets make this fast */
+  /* lets make this fast while ending up with some increass in image size */
+  png_set_filter(png_ptr,0,PNG_FILTER_NONE);
+  /* png_set_filter(png_ptr,0,PNG_FILTER_SUB); */
   png_set_compression_level(png_ptr,1);
-  png_set_filter(png_ptr,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
+  /* png_set_compression_strategy(png_ptr,Z_HUFFMAN_ONLY); */
   /* 
   png_set_filter(png_ptr,PNG_FILTER_TYPE_BASE,PNG_FILTER_SUB);
   png_set_compression_strategy(png_ptr,Z_HUFFMAN_ONLY);
@@ -734,18 +851,152 @@ static int gfx_save_png (art_u8 *buffer, FILE *fp,  long width, long height, lon
   
   png_write_image(png_ptr, row_pointers);
   png_write_end(png_ptr, info_ptr);
+  png_free(png_ptr,row_pointers);
   png_destroy_write_struct(&png_ptr, &info_ptr);
   return 1;
 }
 
  
+/* ----- COMMON ROUTINES for pdf, svg and eps */
+#define min3(a, b, c) (a < b ? (a < c ? a : c) : (b < c ? b : c))
+#define max3(a, b, c) (a > b ? (a > c ? a : c) : (b > c ? b : c))
+
+#define PDF_CALC_DEBUG 0
+
+typedef struct pdf_point
+{
+       double x, y;
+} pdf_point;
+
+typedef struct
+{
+       double ascender, descender, baselineY;
+       pdf_point sizep, minp, maxp;
+       double x, y, tdx, tdy;
+       double r, cos_r, sin_r;
+       double ma, mb, mc, md, mx, my; /* pdf coord matrix */
+       double tmx, tmy; /* last 2 coords of text coord matrix */
+#if PDF_CALC_DEBUG
+       int debug;
+#endif
+} pdf_coords;
+
+#if PDF_CALC_DEBUG
+static void pdf_dump_calc(gfx_node_t *node, pdf_coords *g)
+{
+       fprintf(stderr, "PDF CALC =============================\n");
+       fprintf(stderr, "   '%s' at %f pt\n", node->text, node->size);
+       fprintf(stderr, "   align h = %s, v = %s,  sizep = %f, %f\n",
+               (node->halign == GFX_H_RIGHT ? "r" :
+                       (node->halign == GFX_H_CENTER ? "c" :
+                               (node->halign == GFX_H_LEFT ? "l" : "N"))),
+               (node->valign == GFX_V_TOP ? "t" :
+                       (node->valign == GFX_V_CENTER ? "c" :
+                               (node->valign == GFX_V_BOTTOM ? "b" : "N"))),
+                       g->sizep.x, g->sizep.y);
+       fprintf(stderr, "   r = %f = %f, cos = %f, sin = %f\n",
+                       g->r, node->angle, g->cos_r, g->sin_r);
+       fprintf(stderr, "   ascender = %f, descender = %f, baselineY = %f\n",
+               g->ascender, g->descender, g->baselineY);
+       fprintf(stderr, "   sizep: %f, %f\n", g->sizep.x, g->sizep.y);
+       fprintf(stderr, "   minp: %f, %f     maxp = %f, %f\n", 
+                       g->minp.x, g->minp.y, g->maxp.x, g->maxp.y);
+       fprintf(stderr, "   x = %f, y = %f\n", g->x, g->y);
+       fprintf(stderr, "   tdx = %f, tdy = %f\n", g->tdx, g->tdy);
+       fprintf(stderr, "   GM = %f, %f, %f, %f, %f, %f\n",
+                       g->ma, g->mb, g->mc, g->md, g->mx, g->my);
+       fprintf(stderr, "   TM = %f, %f, %f, %f, %f, %f\n",
+                       g->ma, g->mb, g->mc, g->md, g->tmx, g->tmy);
+}
+#endif
+#if PDF_CALC_DEBUG
+#define PDF_DD(x) if (g->debug) x;
+#else
+#define PDF_DD(x)
+#endif
+
+static void pdf_rotate(pdf_coords *g, pdf_point *p)
+{
+    double x2 = g->cos_r * p->x - g->sin_r * p->y;
+    double y2 = g->sin_r * p->x + g->cos_r * p->y;
+       PDF_DD( fprintf(stderr, "  rotate(%f, %f) -> %f, %f\n", p->x, p->y, x2, y2))
+    p->x = x2;
+       p->y = y2;
+}
+
+
+static void pdf_calc(int page_height, gfx_node_t *node, pdf_coords *g)
+{
+       pdf_point a, b, c;
+#if PDF_CALC_DEBUG
+       /* g->debug = !!strstr(node->text, "RevProxy-1") || !!strstr(node->text, "08:00"); */
+       g->debug = !!strstr(node->text, "sekunder") || !!strstr(node->text, "Web");
+#endif
+       g->x = node->x;
+       g->y = page_height - node->y;
+       if (node->angle) {
+               g->r = 2 * M_PI * node->angle / 360.0;
+               g->cos_r = cos(g->r);
+               g->sin_r = sin(g->r);
+       } else {
+               g->r = 0;
+               g->cos_r = 1;
+               g->sin_r = 0;
+       }
+       g->ascender = afm_get_ascender(node->filename, node->size);
+       g->descender = afm_get_descender(node->filename, node->size);
+       g->sizep.x = afm_get_text_width(0, node->filename, node->size, node->tabwidth, node->text);
+       /* seems like libart ignores the descender when doing vertial-align = bottom,
+          so we do that too, to get labels v-aligning properly */
+       g->sizep.y = -g->ascender; /* + afm_get_descender(font->ps_font, node->size); */
+       g->baselineY = -g->ascender - g->sizep.y / 2;
+       a.x = g->sizep.x; a.y = g->sizep.y;
+       b.x = g->sizep.x; b.y = 0;
+       c.x = 0; c.y = g->sizep.y;
+       if (node->angle) {
+               pdf_rotate(g, &a);
+               pdf_rotate(g, &b);
+               pdf_rotate(g, &c);
+       }
+       g->minp.x = min3(a.x, b.x, c.x);
+       g->minp.y = min3(a.y, b.y, c.y);
+       g->maxp.x = max3(a.x, b.x, c.x);
+       g->maxp.y = max3(a.y, b.y, c.y);
+  /* The alignment parameters in node->valign and node->halign
+     specifies the alignment in the non-rotated coordinate system
+     (very unlike pdf/postscript), which complicates matters.
+  */
+       switch (node->halign) {
+       case GFX_H_RIGHT:  g->tdx = -g->maxp.x; break;
+       case GFX_H_CENTER: g->tdx = -(g->maxp.x + g->minp.x) / 2; break;
+       case GFX_H_LEFT:   g->tdx = -g->minp.x; break;
+       case GFX_H_NULL:   g->tdx = 0; break;
+       }
+       switch(node->valign){
+       case GFX_V_TOP:    g->tdy = -g->maxp.y; break;
+       case GFX_V_CENTER: g->tdy = -(g->maxp.y + g->minp.y) / 2; break;
+       case GFX_V_BOTTOM: g->tdy = -g->minp.y; break;
+       case GFX_V_NULL:   g->tdy = 0; break;          
+       }
+       g->ma = g->cos_r;
+       g->mb = g->sin_r;
+       g->mc = -g->sin_r;
+       g->md = g->cos_r;
+       g->mx = g->x + g->tdx;
+       g->my = g->y + g->tdy;
+       g->tmx = g->mx - g->ascender * g->mc;
+       g->tmy = g->my - g->ascender * g->md;
+       PDF_DD(pdf_dump_calc(node, g))
+}
+
 /* ------- SVG -------
    SVG reference:
    http://www.w3.org/TR/SVG/
 */
 static int svg_indent = 0;
 static int svg_single_line = 0;
-static const char *svg_default_font = "Helvetica";
+static const char *svg_default_font = "-dummy-";
 typedef struct svg_dash
 {
   int dash_enable;
@@ -808,37 +1059,50 @@ static void svg_close_tag_empty_node(FILE *fp)
  
 static void svg_write_text(FILE *fp, const char *text)
 {
-   const unsigned char *p, *start, *last;
-   unsigned int ch;
-   p = (const unsigned char*)text;
-   if (!p)
-     return;
-   /* trim leading spaces */
-   while (*p == ' ')
-     p++;
-   start = p;
-   /* trim trailing spaces */
-   last = p - 1;
-   while ((ch = *p) != 0) {
-     if (ch != ' ')
-       last = p;
-     p++;
-  }
-  /* encode trimmed text */
-  p = start;
-  while (p <= last) {
+#ifdef HAVE_MBSTOWCS
+    size_t clen;
+    wchar_t *p, *cstr, ch;
+    int text_count;
+    if (!text)
+       return;
+    clen = strlen(text) + 1;
+    cstr = malloc(sizeof(wchar_t) * clen);
+    text_count = mbstowcs(cstr, text, clen);
+    if (text_count == -1)
+       text_count = mbstowcs(cstr, "Enc-Err", 6);
+    p = cstr;
+#else
+    unsigned char *p = text;
+    unsigned char *cstr;
+    char ch;
+    if (!p)
+       return;
+#endif
+  while (1) {
     ch = *p++;
-    ch = afm_host2unicode(ch); /* unsafe macro */
+    ch = afm_fix_osx_charset(ch); /* unsafe macro */
     switch (ch) {
+    case 0:
+#ifdef HAVE_MBSTOWCS
+    free(cstr);
+#endif
+    return;
     case '&': fputs("&amp;", fp); break;
     case '<': fputs("&lt;", fp); break;
     case '>': fputs("&gt;", fp); break;
     case '"': fputs("&quot;", fp); break;
     default:
-      if (ch >= 127)
-       fprintf(fp, "&#%d;", ch);
+        if (ch == 32) {
+#ifdef HAVE_MBSTOWCS
+            if (p <= cstr + 1 || !*p || *p == 32)
+                fputs("&#160;", fp); /* non-breaking space in unicode */
+            else
+#endif
+                fputc(32, fp);
+        } else if (ch < 32 || ch >= 127)
+       fprintf(fp, "&#%d;", (int)ch);
       else
-       putc(ch, fp);
+       putc((char)ch, fp);
      }
    }
 }
@@ -893,7 +1157,7 @@ static void svg_write_color(FILE *fp, gfx_color_t c, const char *attr)
    }
   fputs("\"", fp);
   if (opacity != 0xFF) {
-    fprintf(fp, " stroke-opacity=\"");
+    fprintf(fp, " opacity=\"");
     svg_write_number(fp, opacity / 255.0);
     fputs("\"", fp);
  }
@@ -1122,47 +1386,37 @@ static void svg_area(FILE *fp, gfx_node_t *node)
  
 static void svg_text(FILE *fp, gfx_node_t *node)
 {
-   double x = node->x - LINEOFFSET;
-   double y = node->y - LINEOFFSET;
+   pdf_coords g;
+   const char *fontname;
+   /* as svg has 0,0 in top-left corner (like most screens) instead of
+         bottom-left corner like pdf and eps, we have to fake the coords
+         using offset and inverse sin(r) value */
+   int page_height = 1000;
+   pdf_calc(page_height, node, &g);
    if (node->angle != 0) {
      svg_start_tag(fp, "g");
-     fputs(" transform=\"translate(", fp);
-     svg_write_number(fp, x);
-     fputs(",", fp);
-     svg_write_number(fp, y);
-     fputs(") rotate(", fp);
-     svg_write_number(fp, node->angle);
-     fputs(")\"", fp);
-     x = y = 0;
+        /* can't use svg_write_number as 2 decimals is far from enough to avoid
+               skewed text */
+     fprintf(fp, " transform=\"matrix(%f,%f,%f,%f,%f,%f)\"",
+                        g.ma, -g.mb, -g.mc, g.md, g.tmx, page_height - g.tmy);
      svg_close_tag(fp);
    }
-   switch (node->valign) {
-   case GFX_V_TOP:  y += node->size; break;
-   case GFX_V_CENTER: y += node->size / 3; break;
-   case GFX_V_BOTTOM: break;
-   case GFX_V_NULL: break;
-   }
    svg_start_tag(fp, "text");
-   fputs(" x=\"", fp);
-   svg_write_number(fp, x);
-   fputs("\" y=\"", fp);
-   svg_write_number(fp, y);
-
-/*  if (strcmp(node->filename, svg_default_font))
-    fprintf(fp, " font-family=\"%s\"", node->filename);
-    */
-   fputs("\" font-family=\"Helvetica", fp);
-   fputs("\" font-size=\"", fp);
+   if (!node->angle) {
+     fputs(" x=\"", fp);
+     svg_write_number(fp, g.tmx);
+     fputs("\" y=\"", fp);
+     svg_write_number(fp, page_height - g.tmy);
+     fputs("\"", fp);
+   }
+   fontname = afm_get_font_name(node->filename);
+   if (strcmp(fontname, svg_default_font))
+     fprintf(fp, " font-family=\"%s\"", fontname);
+   fputs(" font-size=\"", fp);
    svg_write_number(fp, node->size);
    fputs("\"", fp);
   if (!svg_color_is_black(node->color))
     svg_write_color(fp, node->color, "fill");
-   switch (node->halign) {
-   case GFX_H_RIGHT:  fputs(" text-anchor=\"end\"", fp); break;
-   case GFX_H_CENTER: fputs(" text-anchor=\"middle\"", fp); break;
-   case GFX_H_LEFT: break;
-   case GFX_H_NULL: break;
-   }
    svg_close_tag_single_line(fp);
    /* support for node->tabwidth missing */
    svg_write_text(fp, node->text);
@@ -1175,13 +1429,22 @@ int       gfx_render_svg (gfx_canvas_t *canvas,
                  art_u32 width, art_u32 height,
                  gfx_color_t background, FILE *fp){
    gfx_node_t *node = canvas->firstnode;
+   /* Find the first font used, and assume it is the mostly used
+         one. It reduces the number of font-familty attributes. */
+   while (node) {
+          if (node->type == GFX_TEXT && node->filename) {
+                  svg_default_font = afm_get_font_name(node->filename);
+                  break;
+          }
+          node = node->next;
+   }
    fputs(
 "<?xml version=\"1.0\" standalone=\"no\"?>\n"
 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\"\n"
 "   \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"
 "<!--\n"
-"   SVG file created by RRDtool,\n"
-"   Tobias Oetiker <tobi@oetike.ch>, http://tobi.oetiker.ch\n"
+"   SVG file created by\n"
+"        RRDtool " PACKAGE_VERSION " Tobias Oetiker, http://tobi.oetiker.ch\n"
 "\n"
 "   The width/height attributes in the outhermost svg node\n"
 "   are just default sizes for the browser which is used\n"
@@ -1191,9 +1454,9 @@ int       gfx_render_svg (gfx_canvas_t *canvas,
 "-->\n", fp);
    svg_start_tag(fp, "svg");
    fputs(" width=\"", fp);
-  svg_write_number(fp, width * canvas->zoom);
+   svg_write_number(fp, width * canvas->zoom);
    fputs("\" height=\"", fp);
-  svg_write_number(fp, height * canvas->zoom);
+   svg_write_number(fp, height * canvas->zoom);
    fputs("\" x=\"0\" y=\"0\" viewBox=\"", fp);
    svg_write_number(fp, -LINEOFFSET);
    fputs(" ", fp);
@@ -1203,13 +1466,16 @@ int       gfx_render_svg (gfx_canvas_t *canvas,
    fputs(" ", fp);
    svg_write_number(fp, height - LINEOFFSET);
    fputs("\" preserveAspectRatio=\"xMidYMid\"", fp);
-  fprintf(fp, " font-family=\"%s\"", svg_default_font); /* default font */
-  fputs(" stroke-linecap=\"round\" stroke-linejoin=\"round\"", fp);
+   fprintf(fp, " font-family=\"%s\"", svg_default_font); /* default font */
+   fputs(" stroke-linecap=\"round\" stroke-linejoin=\"round\"", fp);
+   fputs(" xmlns=\"http://www.w3.org/2000/svg\"", fp);
+   fputs(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"", fp);
    svg_close_tag(fp);
    svg_start_tag(fp, "rect");
    fprintf(fp, " x=\"0\" y=\"0\" width=\"%d\" height=\"%d\"", width, height);
   svg_write_color(fp, background, "fill");
    svg_close_tag_empty_node(fp);
+   node = canvas->firstnode;
    while (node) {
      switch (node->type) {
      case GFX_LINE:
@@ -1256,13 +1522,26 @@ typedef struct eps_state
 
 static void eps_set_color(eps_state *state, gfx_color_t color)
 {
+#if USE_EPS_FAKE_ALPHA
+   double a1, a2;
+#endif
+   /* gfx_color_t is RRGGBBAA */
+  if (state->color == color)
+    return;
+#if USE_EPS_FAKE_ALPHA
+  a1 = (color & 255) / 255.0;
+  a2 = 255 * (1 - a1);
+#define eps_color_calc(x) (int)( ((x) & 255) * a1 + a2)
+#else
+#define eps_color_calc(x) (int)( (x) & 255)
+#endif
    /* gfx_color_t is RRGGBBAA */
   if (state->color == color)
     return;
   fprintf(state->fp, "%d %d %d Rgb\n",
-      (int)((color >> 24) & 255),
-      (int)((color >> 16) & 255),
-      (int)((color >>  8) & 255));
+      eps_color_calc(color >> 24),
+      eps_color_calc(color >> 16),
+      eps_color_calc(color >>  8));
   state->color = color;
 }
 
@@ -1335,7 +1614,7 @@ static int eps_prologue(eps_state *state)
   gfx_node_t *node;
   fputs(
     "%!PS-Adobe-3.0 EPSF-3.0\n"
-    "%%Creator: RRDtool 1.1.x, Tobias Oetiker, http://tobi.oetiker.ch\n"
+    "%%Creator: RRDtool " PACKAGE_VERSION " Tobias Oetiker, http://tobi.oetiker.ch\n"
     /* can't like weird chars here */
     "%%Title: (RRDtool output)\n"
     "%%DocumentData: Clean7Bit\n"
@@ -1365,12 +1644,9 @@ static int eps_prologue(eps_state *state)
       "/CP {closepath} bd\n"
       "/WS {setlinewidth stroke} bd\n"
       "/F {fill} bd\n"
-      "/TaL { } bd\n"
-      "/TaC {dup stringwidth pop neg 2 div 0 rmoveto } bd\n"
-      "/TaR {dup stringwidth pop neg 0 rmoveto } bd\n"
-      "/TL {moveto TaL show} bd\n"
-      "/TC {moveto TaC show} bd\n"
-      "/TR {moveto TaR show} bd\n"
+      "/T1 {gsave} bd\n"
+      "/T2 {concat 0 0 moveto show grestore} bd\n"
+      "/T   {moveto show} bd\n"
       "/Rgb { 255.0 div 3 1 roll\n"
       "       255.0 div 3 1 roll \n"
       "       255.0 div 3 1 roll setrgbcolor } bd\n"
@@ -1467,12 +1743,28 @@ static void eps_write_linearea(eps_state *state, gfx_node_t *node)
 static void eps_write_text(eps_state *state, gfx_node_t *node)
 {
   FILE *fp = state->fp;
-  const unsigned char *p;
   const char *ps_font = afm_get_font_postscript_name(node->filename);
-  char align = 'L';
-  double x = node->x;
-  double y = state->page_height - node->y, ydelta = 0;
   int lineLen = 0;
+  pdf_coords g;
+#ifdef HAVE_MBSTOWCS
+    size_t clen;
+    wchar_t *p, *cstr, ch;
+    int text_count;
+    if (!node->text)
+       return;
+    clen = strlen(node->text) + 1;
+    cstr = malloc(sizeof(wchar_t) * clen);
+    text_count = mbstowcs(cstr, node->text, clen);
+    if (text_count == -1)
+       text_count = mbstowcs(cstr, "Enc-Err", 6);
+    p = cstr;
+#else
+    const unsigned char *p = node->text;
+    unsigned char ch;
+    if (!p)
+       return;
+#endif
+  pdf_calc(state->page_height, node, &g);
   eps_set_color(state, node->color);
   if (strcmp(ps_font, state->font) || node->size != state->font_size) {
     state->font = ps_font;
@@ -1480,66 +1772,62 @@ static void eps_write_text(eps_state *state, gfx_node_t *node)
     svg_write_number(fp, state->font_size);
     fprintf(fp, " SetFont-%s\n", state->font);
   }
+  if (node->angle)
+         fputs("T1 ", fp);
   fputs("(", fp);
   lineLen = 20;
-  for (p = (const unsigned char*)node->text; *p; p++) {
-    if (lineLen > 70) {
+  while (1) {
+    ch = *p;
+    if (!ch)
+      break;
+       ch = afm_fix_osx_charset(ch); /* unsafe macro */
+    if (++lineLen > 70) {
       fputs("\\\n", fp); /* backslash and \n */
       lineLen = 0;
     }
-    switch (*p) {
+    switch (ch) {
+      case '%':
       case '(':
       case ')':
       case '\\':
+        fputc('\\', fp);
+        fputc(ch, fp);
+        break;
       case '\n':
+        fputs("\\n", fp);
+        break;
       case '\r':
+        fputs("\\r", fp);
+        break;
       case '\t':
-        fputc('\\', fp);
-        lineLen++;
-        /* fall-through */
+        fputs("\\t", fp);
+        break;
       default:
-        if (*p >= 126)
-          fprintf(fp, "\\%03o", *p);
-        else
-          fputc(*p, fp);
-        lineLen++;
-    }
-  }
-  fputs(") ", fp);
-  switch(node->valign){
-  case GFX_V_TOP:    ydelta = -node->size; break;
-  case GFX_V_CENTER: ydelta = -node->size / 3.0; break;          
-  case GFX_V_BOTTOM: break;          
-  case GFX_V_NULL: break;          
-  }
-  if (node->angle == 0)
-    y += ydelta;
-  switch (node->halign) {
-  case GFX_H_RIGHT:  align = 'R'; break;
-  case GFX_H_CENTER: align = 'C'; break;
-  case GFX_H_LEFT: align= 'L'; break;
-  case GFX_H_NULL: align= 'L'; break;
+        if (ch > 255) {
+            fputc('?', fp);
+        } else if (ch >= 126 || ch < 32) {
+          fprintf(fp, "\\%03o", (unsigned int)ch);
+          lineLen += 3;
+        } else {
+          fputc(ch, fp);
+        }
+      }
+      p++;
   }
-  if (node->angle != 0) {
-    fputs("\n", fp);
-    fputs("  gsave ", fp);
-    svg_write_number(fp, x);
-    fputc(' ', fp);
-    svg_write_number(fp, y);
-    fputs(" translate ", fp);
-    svg_write_number(fp, -node->angle);
-    fputs(" rotate 0 ", fp);
-    svg_write_number(fp, ydelta);
-    fputs(" moveto ", fp);
-    fprintf(fp, "Ta%c", align);
-    fputs(" show grestore\n", fp);
+#ifdef HAVE_MBSTOWCS
+  free(cstr);
+#endif
+  if (node->angle) {
+        /* can't use svg_write_number as 2 decimals is far from enough to avoid
+               skewed text */
+         fprintf(fp, ") [%f %f %f %f %f %f] T2\n",
+                         g.ma, g.mb, g.mc, g.md, g.tmx, g.tmy);
   } else {
-    svg_write_number(fp, x);
-    fputc(' ', fp);
-    svg_write_number(fp, y);
-    fputs(" T", fp);
-    fputc(align, fp);
-    fputc('\n', fp);
+         fputs(") ", fp);
+         svg_write_number(fp, g.tmx);
+         fputs(" ", fp);
+         svg_write_number(fp, g.tmy);
+         fputs(" T\n", fp);
   }
 }
 
@@ -1576,6 +1864,7 @@ int       gfx_render_eps (gfx_canvas_t *canvas,
   state.linecap = -1;
   state.linejoin = -1;
   state.has_dash = 0;
+  state.line_width = 1;
   if (eps_prologue(&state) == -1)
     return -1;
   eps_set_color(&state, background);
@@ -1595,7 +1884,7 @@ int       gfx_render_eps (gfx_canvas_t *canvas,
 
 /* ------- PDF -------
    PDF references page:
-   http://partners.adobe.com/asn/developer/technotes/acrobatpdf.html
+   http://partners.adobe.com/public/developer/pdf/index_reference.html
 */
 
 typedef struct pdf_buffer
@@ -1633,7 +1922,7 @@ typedef struct pdf_state
   int last_obj_id;
   /*--*/
   pdf_buffer pdf_header;
-  pdf_buffer catalog_obj, pages_obj, page1_obj;
+  pdf_buffer info_obj, catalog_obj, pages_obj, page1_obj;
   pdf_buffer fontsdict_obj;
   pdf_buffer graph_stream;
 } pdf_state;
@@ -1687,6 +1976,17 @@ static void pdf_put(pdf_buffer *buf, const char *text, int len)
   buf->current_size += len;
 }
 
+static void pdf_put_char(pdf_buffer *buf, char c)
+{
+    if (buf->alloc_size >= buf->current_size + 1) {
+       buf->data[buf->current_size++] = c;
+    } else {
+       char tmp[1];
+       tmp[0] = (char)c;
+       pdf_put(buf, tmp, 1);
+    }
+}
+
 static void pdf_puts(pdf_buffer *buf, const char *text)
 {
   pdf_put(buf, text, strlen(text));
@@ -1717,6 +2017,76 @@ static void pdf_putnumber(pdf_buffer *buf, double d)
   pdf_puts(buf, tmp);
 }
 
+static void pdf_put_string_contents_wide(pdf_buffer *buf, const afm_char *text)
+{
+    const afm_char *p = text;
+    while (1) {
+       afm_char ch = *p;
+       ch = afm_fix_osx_charset(ch); /* unsafe macro */
+       switch (ch) {
+           case 0:
+               return;
+           case '(':
+               pdf_puts(buf, "\\(");
+               break;
+           case ')':
+               pdf_puts(buf, "\\)");
+               break;
+           case '\\':
+               pdf_puts(buf, "\\\\");
+               break;
+           case '\n':
+               pdf_puts(buf, "\\n");
+               break;
+           case '\r':
+               pdf_puts(buf, "\\r");
+               break;
+           case '\t':
+               pdf_puts(buf, "\\t");
+               break;
+           default:
+               if (ch > 255) {
+                   pdf_put_char(buf, '?');
+               } else if (ch > 125 || ch < 32) {
+                   pdf_put_char(buf, ch);
+               } else {
+                   char tmp[10];
+                   snprintf(tmp, sizeof(tmp), "\\%03o", (int)ch);
+                   pdf_puts(buf, tmp);
+               }
+       }
+       p++;
+    }
+}
+
+static void pdf_put_string_contents(pdf_buffer *buf, const char *text)
+{
+#ifdef HAVE_MBSTOWCS
+    size_t clen = strlen(text) + 1;
+    wchar_t *cstr = malloc(sizeof(wchar_t) * clen);
+    int text_count = mbstowcs(cstr, text, clen);
+    if (text_count == -1)
+       text_count = mbstowcs(cstr, "Enc-Err", 6);
+    pdf_put_string_contents_wide(buf, cstr);
+#if 0
+    if (*text == 'W') {
+       fprintf(stderr, "Decoding utf8 for '%s'\n", text);
+       wchar_t *p = cstr;
+       char *pp = text;
+       fprintf(stderr, "sz wc = %d\n", sizeof(wchar_t));
+       while (*p) {
+           fprintf(stderr, "  %d = %c  versus %d = %c\n", *p, (char)*p, 255 & (int)*pp, *pp);
+           p++;
+           pp++;
+       }
+    }
+#endif
+    free(cstr);
+#else
+    pdf_put_string_contents_wide(buf, text);
+#endif
+}
+
 static void pdf_init_object(pdf_state *state, pdf_buffer *buf)
 {
   pdf_init_buffer(state, buf);
@@ -1734,14 +2104,24 @@ static void pdf_init_dict(pdf_state *state, pdf_buffer *buf)
 static void pdf_set_color(pdf_buffer *buf, gfx_color_t color,
        gfx_color_t *current_color, const char *op)
 {
+#if USE_PDF_FAKE_ALPHA
+   double a1, a2;
+#endif
    /* gfx_color_t is RRGGBBAA */
   if (*current_color == color)
     return;
-  pdf_putnumber(buf, ((color >> 24) & 255) / 255.0);
+#if USE_PDF_FAKE_ALPHA
+  a1 = (color & 255) / 255.0;
+  a2 = 1 - a1;
+#define pdf_color_calc(x) ( ((x)  & 255) / 255.0 * a1 + a2)
+#else
+#define pdf_color_calc(x) ( ((x)  & 255) / 255.0)
+#endif
+  pdf_putnumber(buf, pdf_color_calc(color >> 24));
   pdf_puts(buf, " ");
-  pdf_putnumber(buf, ((color >> 16) & 255) / 255.0);
+  pdf_putnumber(buf, pdf_color_calc(color >> 16));
   pdf_puts(buf, " ");
-  pdf_putnumber(buf, ((color >>  8) & 255) / 255.0);
+  pdf_putnumber(buf, pdf_color_calc(color >>  8));
   pdf_puts(buf, " ");
   pdf_puts(buf, op);
   pdf_puts(buf, "\n");
@@ -1885,53 +2265,55 @@ static void pdf_write_linearea(pdf_state *state, gfx_node_t *node)
    }
 }
 
+
+static void pdf_write_matrix(pdf_state *state, gfx_node_t *node, pdf_coords *g, int useTM)
+{
+       char tmp[150];
+       pdf_buffer *s = &state->graph_stream;
+       if (node->angle == 0) {
+               pdf_puts(s, "1 0 0 1 ");
+               pdf_putnumber(s, useTM ? g->tmx : g->mx);
+               pdf_puts(s, " ");
+               pdf_putnumber(s, useTM ? g->tmy : g->my);
+       } else {
+                /* can't use svg_write_number as 2 decimals is far from enough to avoid
+                       skewed text */
+               sprintf(tmp, "%f %f %f %f %f %f",
+                               g->ma, g->mb, g->mc, g->md, 
+                               useTM ? g->tmx : g->mx,
+                               useTM ? g->tmy : g->my);
+               pdf_puts(s, tmp);
+       }
+}
+
 static void pdf_write_text(pdf_state *state, gfx_node_t *node, 
     int last_was_text, int next_is_text)
 {
-  char tmp[30];
+  pdf_coords g;
   pdf_buffer *s = &state->graph_stream;
-  const unsigned char *p;
   pdf_font *font = pdf_find_font(state, node);
-  double x = node->x;
-  double y = state->page_height - node->y;
-  double dx = 0, dy = 0;
-  double cos_a = 0, sin_a = 0;
   if (font == NULL) {
     rrd_set_error("font disappeared");
     state->has_failed = 1;
     return;
   }
-  switch(node->valign){
-  case GFX_V_TOP:    dy = -node->size; break;
-  case GFX_V_CENTER: dy = -node->size / 3.0; break;          
-  case GFX_V_BOTTOM: break;          
-  case GFX_V_NULL: break;          
-  }
-  switch (node->halign) {
-  case GFX_H_RIGHT:  dx = -afm_get_text_width(0, font->ps_font, 
-                        node->size, node->tabwidth, node->text);
-                    break;
-  case GFX_H_CENTER: dx = -afm_get_text_width(0, font->ps_font, 
-                        node->size, node->tabwidth, node->text) / 2;
-                    break;
-  case GFX_H_LEFT: break;
-  case GFX_H_NULL: break;
-  }
+  pdf_calc(state->page_height, node, &g);
+#if PDF_CALC_DEBUG
+  pdf_puts(s, "q % debug green box\n");
+  pdf_write_matrix(state, node, &g, 0);
+  pdf_puts(s, " cm\n");
+  pdf_set_fill_color(s, 0x90FF9000);
+  pdf_puts(s, "0 0.4 0 rg\n");
+  pdf_puts(s, "0 0 ");
+  pdf_putnumber(s, g.sizep.x);
+  pdf_puts(s, " ");
+  pdf_putnumber(s, g.sizep.y);
+  pdf_puts(s, " re\n");
+  pdf_puts(s, "f\n");
+  pdf_puts(s, "Q\n");
+#endif
   pdf_set_fill_color(s, node->color);
-  if (node->angle != 0) {
-    double a = 2 * M_PI * -node->angle / 360.0;
-    double new_x, new_y;
-    cos_a = cos(a);
-    sin_a = sin(a);
-    new_x = cos_a * dx - sin_a * dy + x;
-    new_y = sin_a * dx + cos_a * dy + y;
-    x = new_x;
-    y = new_y;
-  } else {
-    x += dx;
-    y += dy;
-  }
-  if (!last_was_text)
+  if (PDF_CALC_DEBUG || !last_was_text)
     pdf_puts(s, "BT\n");
   if (state->font_id != font->obj.id || node->size != state->font_size) {
     state->font_id = font->obj.id;
@@ -1942,44 +2324,12 @@ static void pdf_write_text(pdf_state *state, gfx_node_t *node,
     pdf_putnumber(s, node->size);
     pdf_puts(s, " Tf\n");
   }
-  if (node->angle == 0) {
-    pdf_puts(s, "1 0 0 1 ");
-  } else {
-    pdf_putnumber(s, cos_a);
-    pdf_puts(s, " ");
-    pdf_putnumber(s, sin_a);
-    pdf_puts(s, " ");
-    pdf_putnumber(s, -sin_a);
-    pdf_puts(s, " ");
-    pdf_putnumber(s, cos_a);
-    pdf_puts(s, " ");
-  }
-  pdf_putnumber(s, x);
-  pdf_puts(s, " ");
-  pdf_putnumber(s, y);
+  pdf_write_matrix(state, node, &g, 1);
   pdf_puts(s, " Tm\n");
   pdf_puts(s, "(");
-  for (p = (const unsigned char*)node->text; *p; p++) {
-    switch (*p) {
-      case '(':
-      case ')':
-      case '\\':
-      case '\n':
-      case '\r':
-      case '\t':
-        pdf_puts(s, "\\");
-        /* fall-through */
-      default:
-        if (*p >= 126) {
-          snprintf(tmp, sizeof(tmp), "\\%03o", *p);
-         pdf_puts(s, tmp);
-       } else {
-          pdf_put(s, (const char*)p, 1);
-       }
-    }
-  }
+  pdf_put_string_contents(s, node->text);
   pdf_puts(s, ") Tj\n");
-  if (!next_is_text)
+  if (PDF_CALC_DEBUG || !next_is_text)
     pdf_puts(s, "ET\n");
 }
  
@@ -2006,6 +2356,7 @@ static void pdf_init_document(pdf_state *state)
 {
   pdf_init_buffer(state, &state->pdf_header);
   pdf_init_dict(state, &state->catalog_obj);
+  pdf_init_dict(state, &state->info_obj);
   pdf_init_dict(state, &state->pages_obj);
   pdf_init_dict(state, &state->page1_obj);
   pdf_init_dict(state, &state->fontsdict_obj);
@@ -2019,12 +2370,17 @@ static void pdf_init_document(pdf_state *state)
 
 static void pdf_setup_document(pdf_state *state)
 {
+  const char *creator = "RRDtool " PACKAGE_VERSION " Tobias Oetiker, http://tobi.oetiker.ch";
   /* all objects created by now, so init code can reference them */
   /* HEADER */
   pdf_puts(&state->pdf_header, "%PDF-1.3\n");
   /* following 8 bit comment is recommended by Adobe for
      indicating binary file to file transfer applications */
   pdf_puts(&state->pdf_header, "%\xE2\xE3\xCF\xD3\n");
+  /* INFO */
+  pdf_putsi(&state->info_obj, "/Creator (");
+  pdf_put_string_contents(&state->info_obj, creator);
+  pdf_puts(&state->info_obj, ")\n");
   /* CATALOG */
   pdf_putsi(&state->catalog_obj, "/Type /Catalog\n");
   pdf_putsi(&state->catalog_obj, "/Pages ");
@@ -2109,6 +2465,7 @@ static void pdf_write_to_file(pdf_state *state)
   fprintf(state->fp, "<<\n");
   fprintf(state->fp, "\t/Size %d\n", state->last_obj_id + 1);
   fprintf(state->fp, "\t/Root %d 0 R\n", state->catalog_obj.id);
+  fprintf(state->fp, "\t/Info %d 0 R\n", state->info_obj.id);
   fprintf(state->fp, ">>\n");
   fprintf(state->fp, "startxref\n");
   fprintf(state->fp, "%d\n", xref_pos);
@@ -2133,7 +2490,7 @@ static void pdf_free_resources(pdf_state *state)
 
 int       gfx_render_pdf (gfx_canvas_t *canvas,
                  art_u32 width, art_u32 height,
-                 gfx_color_t background, FILE *fp){
+                 gfx_color_t UNUSED(background), FILE *fp){
   struct pdf_state state;
   memset(&state, 0, sizeof(pdf_state));
   state.fp = fp;
index 0994900453f286984b652abadd01dca7d3b174c3..40b0ee07796fe1c1e41a4db547a3f7f4aacc40aa 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2001
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  ****************************************************************************
  * rrd_gfx.h generic graphics adapter library
  ****************************************************************************/
@@ -8,12 +8,22 @@
 #define RRD_GFX_H
 #define LIBART_COMPILATION
 
+#define y0 libart_y0
+#define y1 libart_y1
+#define gamma libart_gamma
 #include <libart_lgpl/libart.h>
+#include <libart_lgpl/art_rgba.h>
+#include "art_rgba_svp.h"
+#undef gamma
+#undef y0
+#undef y1
+
 
 enum gfx_if_en {IF_PNG=0,IF_SVG,IF_EPS,IF_PDF};
 enum gfx_en { GFX_LINE=0,GFX_AREA,GFX_TEXT };
 enum gfx_h_align_en { GFX_H_NULL=0, GFX_H_LEFT, GFX_H_RIGHT, GFX_H_CENTER };
 enum gfx_v_align_en { GFX_V_NULL=0, GFX_V_TOP,  GFX_V_BOTTOM, GFX_V_CENTER };
+enum gfx_aa_type_en {AA_NORMAL=0,AA_LIGHT,AA_NONE};
 typedef unsigned long gfx_color_t;
 
 typedef struct  gfx_node_t {
@@ -21,13 +31,12 @@ typedef struct  gfx_node_t {
   gfx_color_t   color;        /* color of element  0xRRGGBBAA  alpha 0xff is solid*/
   double        size;         /* font size, line width */
   double        dash_on, dash_off; /* dash line fragments lengths */
-  ArtVpath      *path;        /* path */
   int           closed_path;
   int           points;
   int           points_max;
-  ArtSVP        *svp;         /* svp */
   char *filename;             /* font or image filename */
   char *text;
+  ArtVpath      *path;        /* path */
   double        x,y;          /* position */
   double        angle;        /* text angle */
   enum gfx_h_align_en halign; /* text alignement */
@@ -44,6 +53,8 @@ typedef struct gfx_canvas_t
     enum gfx_if_en imgformat;      /* image format */
     int            interlaced;     /* will the graph be interlaced? */
     double         zoom;           /* zoom for graph */
+    double         font_aa_threshold; /* no anti-aliasing for sizes <= */
+    enum gfx_aa_type_en aa_type;   /* anti-aliasing type (normal/light/none) */
 } gfx_canvas_t;
 
 gfx_canvas_t *gfx_new_canvas (void);
@@ -102,8 +113,9 @@ int           gfx_destroy    (gfx_canvas_t *canvas);
 int       gfx_render_png (gfx_canvas_t *canvas,
                               art_u32 width, art_u32 height,
                               gfx_color_t background, FILE *fo);
-double gfx_get_text_width_libart ( double start, char* font, double size,
-                           double tabwidth, char* text, int rotation);
+double gfx_get_text_width_libart ( gfx_canvas_t *canvas, double start, 
+                char* font, double size, double tabwidth, 
+                char* text, int rotation );
 
 /* SVG support */
 int       gfx_render_svg (gfx_canvas_t *canvas,
index dacaa6f5a7e7db946931357c97ab5634f47a9da0..22439b5771f174ee0e885cacc28540b9c2d6286c 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * RRDtool 1.2.x  Copyright Tobias Oetiker, 1997 - 2005
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  ****************************************************************************
  * rrd__graph.c  produce graphs from data in rrdfiles
  ****************************************************************************/
@@ -7,9 +7,12 @@
 
 #include <sys/stat.h>
 
+#ifdef WIN32
+#include "strftime.h"
+#endif
 #include "rrd_tool.h"
 
-#ifdef WIN32
+#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
 #include <io.h>
 #include <fcntl.h>
 #endif
 /* some constant definitions */
 
 
-#ifdef WIN32
-char rrd_win_default_font[80];
-#endif
 
 #ifndef RRD_DEFAULT_FONT
 /* there is special code later to pick Cour.ttf when running on windows */
-#define RRD_DEFAULT_FONT "VeraMono.ttf"
+#define RRD_DEFAULT_FONT "DejaVuSansMono-Roman.ttf"
 #endif
 
 text_prop_t text_prop[] = {   
-     { 9.0, RRD_DEFAULT_FONT }, /* default */
-     { 11.0, RRD_DEFAULT_FONT }, /* title */
-     { 8.0,  RRD_DEFAULT_FONT }, /* axis */
-     { 9.0, RRD_DEFAULT_FONT }, /* unit */
-     { 9.0, RRD_DEFAULT_FONT }  /* legend */
+     { 8.0, RRD_DEFAULT_FONT }, /* default */
+     { 9.0, RRD_DEFAULT_FONT }, /* title */
+     { 7.0,  RRD_DEFAULT_FONT }, /* axis */
+     { 8.0, RRD_DEFAULT_FONT }, /* unit */
+     { 8.0, RRD_DEFAULT_FONT }  /* legend */
 };
 
 xlab_t xlab[] = {
-    {0,        TMT_SECOND,30, TMT_MINUTE,5,  TMT_MINUTE,5,         0,"%H:%M"},
-    {2,        TMT_MINUTE,1,  TMT_MINUTE,5,  TMT_MINUTE,5,         0,"%H:%M"},
-    {5,        TMT_MINUTE,2,  TMT_MINUTE,10, TMT_MINUTE,10,        0,"%H:%M"},
-    {10,       TMT_MINUTE,5,  TMT_MINUTE,20, TMT_MINUTE,20,        0,"%H:%M"},
-    {30,       TMT_MINUTE,10, TMT_HOUR,1,    TMT_HOUR,1,           0,"%H:%M"},
-    {60,       TMT_MINUTE,30, TMT_HOUR,2,    TMT_HOUR,2,           0,"%H:%M"},
-    {180,      TMT_HOUR,1,    TMT_HOUR,6,    TMT_HOUR,6,           0,"%H:%M"},
-    /*{300,      TMT_HOUR,3,    TMT_HOUR,12,   TMT_HOUR,12,    12*3600,"%a %p"},  this looks silly*/
-    {600,      TMT_HOUR,6,    TMT_DAY,1,     TMT_DAY,1,      24*3600,"%a"},
-    {1800,     TMT_HOUR,12,   TMT_DAY,1,     TMT_DAY,2,      24*3600,"%a"},
-    {3600,     TMT_DAY,1,     TMT_WEEK,1,     TMT_WEEK,1,    7*24*3600,"Week %V"},
-    {3*3600,   TMT_WEEK,1,      TMT_MONTH,1,     TMT_WEEK,2,    7*24*3600,"Week %V"},
-    {6*3600,   TMT_MONTH,1,   TMT_MONTH,1,   TMT_MONTH,1, 30*24*3600,"%b"},
-    {48*3600,  TMT_MONTH,1,   TMT_MONTH,3,   TMT_MONTH,3, 30*24*3600,"%b"},
-    {10*24*3600, TMT_YEAR,1,  TMT_YEAR,1,    TMT_YEAR,1, 365*24*3600,"%y"},
-    {-1,TMT_MONTH,0,TMT_MONTH,0,TMT_MONTH,0,0,""}
+    {0,                 0,   TMT_SECOND,30, TMT_MINUTE,5,  TMT_MINUTE,5,         0,"%H:%M"},
+    {2,                 0,   TMT_MINUTE,1,  TMT_MINUTE,5,  TMT_MINUTE,5,         0,"%H:%M"},
+    {5,                 0,   TMT_MINUTE,2,  TMT_MINUTE,10, TMT_MINUTE,10,        0,"%H:%M"},
+    {10,                0,   TMT_MINUTE,5,  TMT_MINUTE,20, TMT_MINUTE,20,        0,"%H:%M"},
+    {30,                0,   TMT_MINUTE,10, TMT_HOUR,1,    TMT_HOUR,1,           0,"%H:%M"},
+    {60,                0,   TMT_MINUTE,30, TMT_HOUR,2,    TMT_HOUR,2,           0,"%H:%M"},
+    {60,          24*3600,   TMT_MINUTE,30, TMT_HOUR,2,    TMT_HOUR,4,           0,"%a %H:%M"},
+    {180,               0,   TMT_HOUR,1,    TMT_HOUR,6,    TMT_HOUR,6,           0,"%H:%M"},
+    {180,         24*3600,   TMT_HOUR,1,    TMT_HOUR,6,    TMT_HOUR,12,          0,"%a %H:%M"},
+    /*{300,             0,   TMT_HOUR,3,    TMT_HOUR,12,   TMT_HOUR,12,    12*3600,"%a %p"},  this looks silly*/
+    {600,               0,   TMT_HOUR,6,    TMT_DAY,1,     TMT_DAY,1,      24*3600,"%a"},
+    {1200,               0,   TMT_HOUR,6,    TMT_DAY,1,     TMT_DAY,1,      24*3600,"%d"},
+    {1800,              0,   TMT_HOUR,12,   TMT_DAY,1,     TMT_DAY,2,      24*3600,"%a %d"},
+    {2400,              0,   TMT_HOUR,12,   TMT_DAY,1,     TMT_DAY,2,      24*3600,"%a"},
+    {3600,              0,   TMT_DAY,1,     TMT_WEEK,1,    TMT_WEEK,1,   7*24*3600,"Week %V"},
+    {3*3600,            0,   TMT_WEEK,1,    TMT_MONTH,1,   TMT_WEEK,2,   7*24*3600,"Week %V"},
+    {6*3600,            0,   TMT_MONTH,1,   TMT_MONTH,1,   TMT_MONTH,1, 30*24*3600,"%b"},
+    {48*3600,           0,   TMT_MONTH,1,   TMT_MONTH,3,   TMT_MONTH,3, 30*24*3600,"%b"},
+    {315360,            0,   TMT_MONTH,3,   TMT_YEAR,1,    TMT_YEAR,1,  365*24*3600,"%Y"},
+    {10*24*3600,        0,   TMT_YEAR,1,  TMT_YEAR,1,    TMT_YEAR,1, 365*24*3600,"%y"},
+    {-1,0,TMT_MONTH,0,TMT_MONTH,0,TMT_MONTH,0,0,""}
 };
 
-/* sensible logarithmic y label intervals ...
-   the first element of each row defines the possible starting points on the
-   y axis ... the other specify the */
-
-double yloglab[][12]= {{ 1e9, 1,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0 },
-                      {  1e3, 1,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0 },
-                      {  1e1, 1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
-                      /* {  1e1, 1,  5,  0,  0,  0,  0,  0,  0,  0,  0,  0 }, */
-                      {  1e1, 1,  2.5,  5,  7.5,  0,  0,  0,  0,  0,  0,  0 },
-                      {  1e1, 1,  2,  4,  6,  8,  0,  0,  0,  0,  0,  0 },
-                      {  1e1, 1,  2,  3,  4,  5,  6,  7,  8,  9,  0,  0 },
-                      {  0,   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 }};
-
 /* sensible y label intervals ...*/
 
 ylab_t ylab[]= {
@@ -102,9 +94,10 @@ gfx_color_t graph_col[] =   /* default colors */
      0x90909080,   /* grid       */
      0xE0505080,   /* major grid */
      0x000000FF,   /* font       */ 
-     0xFF0000FF,   /* arrow      */
-     0x404040FF    /* axis       */
-};
+     0x802020FF,   /* arrow      */
+     0x202020FF,   /* axis       */
+     0x000000FF    /* frame      */ 
+};     
 
 
 /* #define DEBUG */
@@ -121,11 +114,11 @@ int
 xtr(image_desc_t *im,time_t mytime){
     static double pixie;
     if (mytime==0){
-       pixie = (double) im->xsize / (double)(im->end - im->start);
-       return im->xorigin;
+        pixie = (double) im->xsize / (double)(im->end - im->start);
+        return im->xorigin;
     }
     return (int)((double)im->xorigin 
-                + pixie * ( mytime - im->start ) );
+                 + pixie * ( mytime - im->start ) );
 }
 
 /* translate data values into y coordinates */
@@ -135,17 +128,17 @@ ytr(image_desc_t *im, double value){
     double yval;
     if (isnan(value)){
       if(!im->logarithmic)
-       pixie = (double) im->ysize / (im->maxval - im->minval);
+        pixie = (double) im->ysize / (im->maxval - im->minval);
       else 
-       pixie = (double) im->ysize / (log10(im->maxval) - log10(im->minval));
+        pixie = (double) im->ysize / (log10(im->maxval) - log10(im->minval));
       yval = im->yorigin;
     } else if(!im->logarithmic) {
       yval = im->yorigin - pixie * (value - im->minval);
     } else {
       if (value < im->minval) {
-       yval = im->yorigin;
+        yval = im->yorigin;
       } else {
-       yval = im->yorigin - pixie * (log10(value) - log10(im->minval));
+        yval = im->yorigin - pixie * (log10(value) - log10(im->minval));
       }
     }
     /* make sure we don't return anything too unreasonable. GD lib can
@@ -154,9 +147,9 @@ ytr(image_desc_t *im, double value){
     if (! im->rigid) {
       /* keep yval as-is */
     } else if (yval > im->yorigin) {
-      yval = im->yorigin+2;
+      yval = im->yorigin +0.00001;
     } else if (yval < im->yorigin - im->ysize){
-      yval = im->yorigin - im->ysize - 2;
+      yval = im->yorigin - im->ysize - 0.00001;
     } 
     return yval;
 }
@@ -178,7 +171,7 @@ enum gf_en gf_conv(char *string){
     conv_if(VRULE,GF_VRULE)
     conv_if(LINE,GF_LINE)
     conv_if(AREA,GF_AREA)
-    conv_if(STACK,GF_STACK)
+    conv_if(STACK,GF_STACK) 
     conv_if(TICK,GF_TICK)
     conv_if(DEF,GF_DEF)
     conv_if(CDEF,GF_CDEF)
@@ -225,8 +218,9 @@ enum grc_en grc_conv(char *string){
     conv_if(FONT,GRC_FONT)
     conv_if(ARROW,GRC_ARROW)
     conv_if(AXIS,GRC_AXIS)
+    conv_if(FRAME,GRC_FRAME)
 
-    return -1; 
+    return -1;        
 }
 
 enum text_prop_en text_prop_conv(char *string){
@@ -245,18 +239,18 @@ enum text_prop_en text_prop_conv(char *string){
 int
 im_free(image_desc_t *im)
 {
-    unsigned long      i,ii;
+    unsigned long        i,ii;
 
     if (im == NULL) return 0;
     for(i=0;i<(unsigned)im->gdes_c;i++){
       if (im->gdes[i].data_first){
-       /* careful here, because a single pointer can occur several times */
-         free (im->gdes[i].data);
-         if (im->gdes[i].ds_namv){
-             for (ii=0;ii<im->gdes[i].ds_cnt;ii++)
-                 free(im->gdes[i].ds_namv[ii]);
-             free(im->gdes[i].ds_namv);
-         }
+        /* careful here, because a single pointer can occur several times */
+          free (im->gdes[i].data);
+          if (im->gdes[i].ds_namv){
+              for (ii=0;ii<im->gdes[i].ds_cnt;ii++)
+                  free(im->gdes[i].ds_namv[ii]);
+              free(im->gdes[i].ds_namv);
+          }
       }
       free (im->gdes[i].p_data);
       free (im->gdes[i].rpnp);
@@ -269,47 +263,64 @@ im_free(image_desc_t *im)
 /* find SI magnitude symbol for the given number*/
 void
 auto_scale(
-          image_desc_t *im,   /* image description */
-          double *value,
-          char **symb_ptr,
-          double *magfact
-          )
+           image_desc_t *im,   /* image description */
+           double *value,
+           char **symb_ptr,
+           double *magfact
+           )
 {
-       
+        
     char *symbol[] = {"a", /* 10e-18 Atto */
-                     "f", /* 10e-15 Femto */
-                     "p", /* 10e-12 Pico */
-                     "n", /* 10e-9  Nano */
-                     "u", /* 10e-6  Micro */
-                     "m", /* 10e-3  Milli */
-                     " ", /* Base */
-                     "k", /* 10e3   Kilo */
-                     "M", /* 10e6   Mega */
-                     "G", /* 10e9   Giga */
-                     "T", /* 10e12  Tera */
-                     "P", /* 10e15  Peta */
-                     "E"};/* 10e18  Exa */
+                      "f", /* 10e-15 Femto */
+                      "p", /* 10e-12 Pico */
+                      "n", /* 10e-9  Nano */
+                      "u", /* 10e-6  Micro */
+                      "m", /* 10e-3  Milli */
+                      " ", /* Base */
+                      "k", /* 10e3   Kilo */
+                      "M", /* 10e6   Mega */
+                      "G", /* 10e9   Giga */
+                      "T", /* 10e12  Tera */
+                      "P", /* 10e15  Peta */
+                      "E"};/* 10e18  Exa */
 
     int symbcenter = 6;
     int sindex;  
 
     if (*value == 0.0 || isnan(*value) ) {
-       sindex = 0;
-       *magfact = 1.0;
+        sindex = 0;
+        *magfact = 1.0;
     } else {
-       sindex = floor(log(fabs(*value))/log((double)im->base)); 
-       *magfact = pow((double)im->base, (double)sindex);
-       (*value) /= (*magfact);
+        sindex = floor(log(fabs(*value))/log((double)im->base)); 
+        *magfact = pow((double)im->base, (double)sindex);
+        (*value) /= (*magfact);
     }
     if ( sindex <= symbcenter && sindex >= -symbcenter) {
-       (*symb_ptr) = symbol[sindex+symbcenter];
+        (*symb_ptr) = symbol[sindex+symbcenter];
     }
     else {
-       (*symb_ptr) = "?";
+        (*symb_ptr) = "?";
     }
 }
 
 
+static char si_symbol[] = {
+                     'a', /* 10e-18 Atto */ 
+                     'f', /* 10e-15 Femto */
+                     'p', /* 10e-12 Pico */
+                     'n', /* 10e-9  Nano */
+                     'u', /* 10e-6  Micro */
+                     'm', /* 10e-3  Milli */
+                     ' ', /* Base */
+                     'k', /* 10e3   Kilo */
+                     'M', /* 10e6   Mega */
+                     'G', /* 10e9   Giga */
+                     'T', /* 10e12  Tera */
+                     'P', /* 10e15  Peta */
+                     'E', /* 10e18  Exa */
+};
+static const int si_symbcenter = 6;
+
 /* find SI magnitude symbol for the numbers on the y-axis*/
 void 
 si_unit(
@@ -317,40 +328,30 @@ si_unit(
 )
 {
 
-    char symbol[] = {'a', /* 10e-18 Atto */ 
-                    'f', /* 10e-15 Femto */
-                    'p', /* 10e-12 Pico */
-                    'n', /* 10e-9  Nano */
-                    'u', /* 10e-6  Micro */
-                    'm', /* 10e-3  Milli */
-                    ' ', /* Base */
-                    'k', /* 10e3   Kilo */
-                    'M', /* 10e6   Mega */
-                    'G', /* 10e9   Giga */
-                    'T', /* 10e12  Tera */
-                    'P', /* 10e15  Peta */
-                    'E'};/* 10e18  Exa */
-
-    int   symbcenter = 6;
-    double digits;  
+    double digits,viewdigits=0;  
     
+    digits = floor( log( max( fabs(im->minval),fabs(im->maxval)))/log((double)im->base)); 
+
     if (im->unitsexponent != 9999) {
-       /* unitsexponent = 9, 6, 3, 0, -3, -6, -9, etc */
-        digits = floor(im->unitsexponent / 3);
+        /* unitsexponent = 9, 6, 3, 0, -3, -6, -9, etc */
+        viewdigits = floor(im->unitsexponent / 3);
     } else {
-        digits = floor( log( max( fabs(im->minval),fabs(im->maxval)))/log((double)im->base)); 
+        viewdigits = digits;
     }
-    im->magfact = pow((double)im->base , digits);
 
+    im->magfact = pow((double)im->base , digits);
+    
 #ifdef DEBUG
     printf("digits %6.3f  im->magfact %6.3f\n",digits,im->magfact);
 #endif
 
-    if ( ((digits+symbcenter) < sizeof(symbol)) &&
-                   ((digits+symbcenter) >= 0) )
-        im->symbol = symbol[(int)digits+symbcenter];
+    im->viewfactor = im->magfact / pow((double)im->base , viewdigits);
+
+    if ( ((viewdigits+si_symbcenter) < sizeof(si_symbol)) &&
+                    ((viewdigits+si_symbcenter) >= 0) )
+        im->symbol = si_symbol[(int)viewdigits+si_symbcenter];
     else
-       im->symbol = ' ';
+        im->symbol = '?';
  }
 
 /*  move min and max values around to become sensible */
@@ -359,13 +360,13 @@ void
 expand_range(image_desc_t *im)
 {
     double sensiblevalues[] ={1000.0,900.0,800.0,750.0,700.0,
-                             600.0,500.0,400.0,300.0,250.0,
-                             200.0,125.0,100.0,90.0,80.0,
-                             75.0,70.0,60.0,50.0,40.0,30.0,
-                             25.0,20.0,10.0,9.0,8.0,
-                             7.0,6.0,5.0,4.0,3.5,3.0,
-                             2.5,2.0,1.8,1.5,1.2,1.0,
-                             0.8,0.7,0.6,0.5,0.4,0.3,0.2,0.1,0.0,-1};
+                              600.0,500.0,400.0,300.0,250.0,
+                              200.0,125.0,100.0,90.0,80.0,
+                              75.0,70.0,60.0,50.0,40.0,30.0,
+                              25.0,20.0,10.0,9.0,8.0,
+                              7.0,6.0,5.0,4.0,3.5,3.0,
+                              2.5,2.0,1.8,1.5,1.2,1.0,
+                              0.8,0.7,0.6,0.5,0.4,0.3,0.2,0.1,0.0,-1};
     
     double scaled_min,scaled_max;  
     double adj;
@@ -375,69 +376,76 @@ expand_range(image_desc_t *im)
     
 #ifdef DEBUG
     printf("Min: %6.2f Max: %6.2f MagFactor: %6.2f\n",
-          im->minval,im->maxval,im->magfact);
+           im->minval,im->maxval,im->magfact);
 #endif
 
     if (isnan(im->ygridstep)){
-       if(im->extra_flags & ALTAUTOSCALE) {
-           /* measure the amplitude of the function. Make sure that
-              graph boundaries are slightly higher then max/min vals
-              so we can see amplitude on the graph */
-             double delt, fact;
-
-             delt = im->maxval - im->minval;
-             adj = delt * 0.1;
-             fact = 2.0 * pow(10.0,
-                   floor(log10(max(fabs(im->minval), fabs(im->maxval)))) - 2);
-             if (delt < fact) {
-               adj = (fact - delt) * 0.55;
+        if(im->extra_flags & ALTAUTOSCALE) {
+            /* measure the amplitude of the function. Make sure that
+               graph boundaries are slightly higher then max/min vals
+               so we can see amplitude on the graph */
+              double delt, fact;
+
+              delt = im->maxval - im->minval;
+              adj = delt * 0.1;
+              fact = 2.0 * pow(10.0,
+                    floor(log10(max(fabs(im->minval), fabs(im->maxval))/im->magfact)) - 2);
+              if (delt < fact) {
+                adj = (fact - delt) * 0.55;
 #ifdef DEBUG
-             printf("Min: %6.2f Max: %6.2f delt: %6.2f fact: %6.2f adj: %6.2f\n", im->minval, im->maxval, delt, fact, adj);
+              printf("Min: %6.2f Max: %6.2f delt: %6.2f fact: %6.2f adj: %6.2f\n", im->minval, im->maxval, delt, fact, adj);
 #endif
-             }
-             im->minval -= adj;
-             im->maxval += adj;
-       }
-       else if(im->extra_flags & ALTAUTOSCALE_MAX) {
+              }
+              im->minval -= adj;
+              im->maxval += adj;
+        }
+       else if(im->extra_flags & ALTAUTOSCALE_MIN) {
            /* measure the amplitude of the function. Make sure that
-              graph boundaries are slightly higher than max vals
+              graph boundaries are slightly lower than min vals
               so we can see amplitude on the graph */
              adj = (im->maxval - im->minval) * 0.1;
-             im->maxval += adj;
-       }
-       else {
-           scaled_min = im->minval / im->magfact;
-           scaled_max = im->maxval / im->magfact;
-           
-           for (i=1; sensiblevalues[i] > 0; i++){
-               if (sensiblevalues[i-1]>=scaled_min &&
-                   sensiblevalues[i]<=scaled_min)      
-                   im->minval = sensiblevalues[i]*(im->magfact);
-               
-               if (-sensiblevalues[i-1]<=scaled_min &&
-               -sensiblevalues[i]>=scaled_min)
-                   im->minval = -sensiblevalues[i-1]*(im->magfact);
-               
-               if (sensiblevalues[i-1] >= scaled_max &&
-                   sensiblevalues[i] <= scaled_max)
-                   im->maxval = sensiblevalues[i-1]*(im->magfact);
-               
-               if (-sensiblevalues[i-1]<=scaled_max &&
-                   -sensiblevalues[i] >=scaled_max)
-                   im->maxval = -sensiblevalues[i]*(im->magfact);
-           }
+             im->minval -= adj;
        }
+        else if(im->extra_flags & ALTAUTOSCALE_MAX) {
+            /* measure the amplitude of the function. Make sure that
+               graph boundaries are slightly higher than max vals
+               so we can see amplitude on the graph */
+              adj = (im->maxval - im->minval) * 0.1;
+              im->maxval += adj;
+        }
+        else {
+            scaled_min = im->minval / im->magfact;
+            scaled_max = im->maxval / im->magfact;
+            
+            for (i=1; sensiblevalues[i] > 0; i++){
+                if (sensiblevalues[i-1]>=scaled_min &&
+                    sensiblevalues[i]<=scaled_min)        
+                    im->minval = sensiblevalues[i]*(im->magfact);
+                
+                if (-sensiblevalues[i-1]<=scaled_min &&
+                -sensiblevalues[i]>=scaled_min)
+                    im->minval = -sensiblevalues[i-1]*(im->magfact);
+                
+                if (sensiblevalues[i-1] >= scaled_max &&
+                    sensiblevalues[i] <= scaled_max)
+                    im->maxval = sensiblevalues[i-1]*(im->magfact);
+                
+                if (-sensiblevalues[i-1]<=scaled_max &&
+                    -sensiblevalues[i] >=scaled_max)
+                    im->maxval = -sensiblevalues[i]*(im->magfact);
+            }
+        }
     } else {
-       /* adjust min and max to the grid definition if there is one */
-       im->minval = (double)im->ylabfact * im->ygridstep * 
-           floor(im->minval / ((double)im->ylabfact * im->ygridstep));
-       im->maxval = (double)im->ylabfact * im->ygridstep * 
-           ceil(im->maxval /( (double)im->ylabfact * im->ygridstep));
+        /* adjust min and max to the grid definition if there is one */
+        im->minval = (double)im->ylabfact * im->ygridstep * 
+            floor(im->minval / ((double)im->ylabfact * im->ygridstep));
+        im->maxval = (double)im->ylabfact * im->ygridstep * 
+            ceil(im->maxval /( (double)im->ylabfact * im->ygridstep));
     }
     
 #ifdef DEBUG
     fprintf(stderr,"SCALED Min: %6.2f Max: %6.2f Factor: %6.2f\n",
-          im->minval,im->maxval,im->magfact);
+           im->minval,im->maxval,im->magfact);
 #endif
 }
 
@@ -458,14 +466,14 @@ apply_gridfit(image_desc_t *im)
     yb = ya * 10;
     if (yb <= im->maxval) {
       /* we have at least 2 y=10^x gridlines.
-        Make sure distance between them in pixels
-        are an integer by expanding im->maxval */
+         Make sure distance between them in pixels
+         are an integer by expanding im->maxval */
       double y_pixel_delta = ytr(im, ya) - ytr(im, yb);
       double factor = y_pixel_delta / floor(y_pixel_delta);
       double new_log10_range = factor * log10_range;
       double new_ymax_log10 = log10(im->minval) + new_log10_range;
       im->maxval = pow(10, new_ymax_log10);
-      ytr(im, DNAN); /* reset precalc */
+      ytr(im,DNAN); /* reset precalc */
       log10_range = log10(im->maxval) - log10(im->minval);
     }
     /* make sure first y=10^x gridline is located on 
@@ -477,7 +485,7 @@ apply_gridfit(image_desc_t *im)
       double yfrac = ypixfrac / im->ysize;
       im->minval = pow(10, log10(im->minval) - yfrac * log10_range);
       im->maxval = pow(10, log10(im->maxval) - yfrac * log10_range);
-      ytr(im, DNAN); /* reset precalc */
+      ytr(im,DNAN); /* reset precalc */
     }
   } else {
     /* Make sure we have an integer pixel distance between
@@ -489,8 +497,11 @@ apply_gridfit(image_desc_t *im)
     double new_range = factor * (im->maxval - im->minval);
     double gridstep = im->ygrid_scale.gridstep;
     double minor_y, minor_y_px, minor_y_px_frac;
-    im->maxval = im->minval + new_range;
-    ytr(im, DNAN); /* reset precalc */
+    if (im->maxval > 0.0)
+      im->maxval = im->minval + new_range;
+    else
+      im->minval = im->maxval - new_range;
+    ytr(im,DNAN); /* reset precalc */
     /* make sure first minor gridline is on integer pixel y coord */
     minor_y = gridstep * floor(im->minval / gridstep);
     while (minor_y < im->minval)
@@ -502,7 +513,7 @@ apply_gridfit(image_desc_t *im)
       double range = im->maxval - im->minval;
       im->minval = im->minval - yfrac * range;
       im->maxval = im->maxval - yfrac * range;
-      ytr(im, DNAN); /* reset precalc */
+      ytr(im,DNAN); /* reset precalc */
     }
     calc_horizontal_grid(im); /* recalc with changed im->maxval */
   }
@@ -534,11 +545,11 @@ reduce_data(
 #endif
 #ifdef DEBUG_REDUCE
 printf("Reducing %lu rows with factor %i time %lu to %lu, step %lu\n",
-                       row_cnt,reduce_factor,*start,*end,cur_step);
+                        row_cnt,reduce_factor,*start,*end,cur_step);
 for (col=0;col<row_cnt;col++) {
     printf("time %10lu: ",*start+(col+1)*cur_step);
     for (i=0;i<*ds_cnt;i++)
-       printf(" %8.2e",srcptr[*ds_cnt*col+i]);
+        printf(" %8.2e",srcptr[*ds_cnt*col+i]);
     printf("\n");
 }
 #endif
@@ -565,11 +576,11 @@ printf("start_offset: %lu  end_offset: %lu\n",start_offset,end_offset);
 printf("row_cnt before:  %lu\n",row_cnt);
 #endif
     if (start_offset) {
-       (*start) = (*start)-start_offset;
-       skiprows=reduce_factor-start_offset/cur_step;
-       srcptr+=skiprows* *ds_cnt;
+        (*start) = (*start)-start_offset;
+        skiprows=reduce_factor-start_offset/cur_step;
+        srcptr+=skiprows* *ds_cnt;
         for (col=0;col<(*ds_cnt);col++) *dstptr++ = DNAN;
-       row_cnt-=skiprows;
+        row_cnt-=skiprows;
     }
 #ifdef DEBUG_REDUCE
 printf("row_cnt between: %lu\n",row_cnt);
@@ -579,9 +590,9 @@ printf("row_cnt between: %lu\n",row_cnt);
     ** used, the amount is end_offset/cur_step
     */
     if (end_offset) {
-       (*end) = (*end)-end_offset+(*step);
-       skiprows = end_offset/cur_step;
-       row_cnt-=skiprows;
+        (*end) = (*end)-end_offset+(*step);
+        skiprows = end_offset/cur_step;
+        row_cnt-=skiprows;
     }
 #ifdef DEBUG_REDUCE
 printf("row_cnt after:   %lu\n",row_cnt);
@@ -591,10 +602,10 @@ printf("row_cnt after:   %lu\n",row_cnt);
 /* if this gets triggered, something is REALLY WRONG ... we die immediately */
 
     if (row_cnt%reduce_factor) {
-       printf("SANITY CHECK: %lu rows cannot be reduced by %i \n",
-                               row_cnt,reduce_factor);
-       printf("BUG in reduce_data()\n");
-       exit(1);
+        printf("SANITY CHECK: %lu rows cannot be reduced by %i \n",
+                                row_cnt,reduce_factor);
+        printf("BUG in reduce_data()\n");
+        exit(1);
     }
 
     /* Now combine reduce_factor intervals at a time
@@ -602,59 +613,59 @@ printf("row_cnt after:   %lu\n",row_cnt);
     */
 
     for (dst_row=0;(long int)row_cnt>=reduce_factor;dst_row++) {
-       for (col=0;col<(*ds_cnt);col++) {
-           rrd_value_t newval=DNAN;
-           unsigned long validval=0;
-
-           for (i=0;i<reduce_factor;i++) {
-               if (isnan(srcptr[i*(*ds_cnt)+col])) {
-                   continue;
-               }
-               validval++;
-               if (isnan(newval)) newval = srcptr[i*(*ds_cnt)+col];
-               else {
-                   switch (cf) {
-                       case CF_HWPREDICT:
-                       case CF_DEVSEASONAL:
-                       case CF_DEVPREDICT:
-                       case CF_SEASONAL:
-                       case CF_AVERAGE:
-                           newval += srcptr[i*(*ds_cnt)+col];
-                           break;
-                       case CF_MINIMUM:
-                           newval = min (newval,srcptr[i*(*ds_cnt)+col]);
-                           break;
-                       case CF_FAILURES: 
-                       /* an interval contains a failure if any subintervals contained a failure */
-                       case CF_MAXIMUM:
-                           newval = max (newval,srcptr[i*(*ds_cnt)+col]);
-                           break;
-                       case CF_LAST:
-                           newval = srcptr[i*(*ds_cnt)+col];
-                           break;
-                   }
-               }
-           }
-           if (validval == 0){newval = DNAN;} else{
-               switch (cf) {
-                   case CF_HWPREDICT:
-           case CF_DEVSEASONAL:
-                   case CF_DEVPREDICT:
-                   case CF_SEASONAL:
-                   case CF_AVERAGE:                
-                      newval /= validval;
-                       break;
-                   case CF_MINIMUM:
-                   case CF_FAILURES:
-                   case CF_MAXIMUM:
-                   case CF_LAST:
-                       break;
-               }
-           }
-           *dstptr++=newval;
-       }
-       srcptr+=(*ds_cnt)*reduce_factor;
-       row_cnt-=reduce_factor;
+        for (col=0;col<(*ds_cnt);col++) {
+            rrd_value_t newval=DNAN;
+            unsigned long validval=0;
+
+            for (i=0;i<reduce_factor;i++) {
+                if (isnan(srcptr[i*(*ds_cnt)+col])) {
+                    continue;
+                }
+                validval++;
+                if (isnan(newval)) newval = srcptr[i*(*ds_cnt)+col];
+                else {
+                    switch (cf) {
+                        case CF_HWPREDICT:
+                        case CF_DEVSEASONAL:
+                        case CF_DEVPREDICT:
+                        case CF_SEASONAL:
+                        case CF_AVERAGE:
+                            newval += srcptr[i*(*ds_cnt)+col];
+                            break;
+                        case CF_MINIMUM:
+                            newval = min (newval,srcptr[i*(*ds_cnt)+col]);
+                            break;
+                        case CF_FAILURES: 
+                        /* an interval contains a failure if any subintervals contained a failure */
+                        case CF_MAXIMUM:
+                            newval = max (newval,srcptr[i*(*ds_cnt)+col]);
+                            break;
+                        case CF_LAST:
+                            newval = srcptr[i*(*ds_cnt)+col];
+                            break;
+                    }
+                }
+            }
+            if (validval == 0){newval = DNAN;} else{
+                switch (cf) {
+                    case CF_HWPREDICT:
+                case CF_DEVSEASONAL:
+                    case CF_DEVPREDICT:
+                    case CF_SEASONAL:
+                    case CF_AVERAGE:                
+                       newval /= validval;
+                        break;
+                    case CF_MINIMUM:
+                    case CF_FAILURES:
+                     case CF_MAXIMUM:
+                    case CF_LAST:
+                        break;
+                }
+            }
+            *dstptr++=newval;
+        }
+        srcptr+=(*ds_cnt)*reduce_factor;
+        row_cnt-=reduce_factor;
     }
     /* If we had to alter the endtime, we didn't have enough
     ** source rows to fill the last row. Fill it with NaN.
@@ -664,11 +675,11 @@ printf("row_cnt after:   %lu\n",row_cnt);
     row_cnt = ((*end)-(*start))/ *step;
     srcptr = *data;
     printf("Done reducing. Currently %lu rows, time %lu to %lu, step %lu\n",
-                               row_cnt,*start,*end,*step);
+                                row_cnt,*start,*end,*step);
 for (col=0;col<row_cnt;col++) {
     printf("time %10lu: ",*start+(col+1)*(*step));
     for (i=0;i<*ds_cnt;i++)
-       printf(" %8.2e",srcptr[*ds_cnt*col+i]);
+        printf(" %8.2e",srcptr[*ds_cnt*col+i]);
     printf("\n");
 }
 #endif
@@ -682,80 +693,79 @@ int
 data_fetch(image_desc_t *im )
 {
     int i,ii;
-    int                skip;
+    int                skip;
 
-    /* pull the data from the log files ... */
+    /* pull the data from the rrd files ... */
     for (i=0;i< (int)im->gdes_c;i++){
-       /* only GF_DEF elements fetch data */
-       if (im->gdes[i].gf != GF_DEF) 
-           continue;
-
-       skip=0;
-       /* do we have it already ?*/
-       for (ii=0;ii<i;ii++) {
-           if (im->gdes[ii].gf != GF_DEF) 
-               continue;
-           if ((strcmp(im->gdes[i].rrd, im->gdes[ii].rrd) == 0)
-                       && (im->gdes[i].cf    == im->gdes[ii].cf)
-                       && (im->gdes[i].cf_reduce == im->gdes[ii].cf_reduce)
-                       && (im->gdes[i].start == im->gdes[ii].start)
-                       && (im->gdes[i].end   == im->gdes[ii].end)
-                       && (im->gdes[i].step  == im->gdes[ii].step)) {
-               /* OK, the data is already there.
-               ** Just copy the header portion
-               */
-               im->gdes[i].start = im->gdes[ii].start;
-               im->gdes[i].end = im->gdes[ii].end;
-               im->gdes[i].step = im->gdes[ii].step;
-               im->gdes[i].ds_cnt = im->gdes[ii].ds_cnt;
-               im->gdes[i].ds_namv = im->gdes[ii].ds_namv;             
-               im->gdes[i].data = im->gdes[ii].data;
-               im->gdes[i].data_first = 0;
-               skip=1;
-           }
-           if (skip) 
-               break;
-       }
-       if (! skip) {
-           unsigned long  ft_step = im->gdes[i].step ;
-           
-           if((rrd_fetch_fn(im->gdes[i].rrd,
-                            im->gdes[i].cf,
-                            &im->gdes[i].start,
-                            &im->gdes[i].end,
-                            &ft_step,
-                            &im->gdes[i].ds_cnt,
-                            &im->gdes[i].ds_namv,
-                            &im->gdes[i].data)) == -1){                
-               return -1;
-           }
-           im->gdes[i].data_first = 1;     
-           im->gdes[i].step = im->step;
-       
-           if (ft_step < im->gdes[i].step) {
-               reduce_data(im->gdes[i].cf_reduce,
-                           ft_step,
-                           &im->gdes[i].start,
-                           &im->gdes[i].end,
-                           &im->gdes[i].step,
-                           &im->gdes[i].ds_cnt,
-                           &im->gdes[i].data);
-           } else {
-               im->gdes[i].step = ft_step;
-           }
-       }
-       
+        /* only GF_DEF elements fetch data */
+        if (im->gdes[i].gf != GF_DEF) 
+            continue;
+
+        skip=0;
+        /* do we have it already ?*/
+        for (ii=0;ii<i;ii++) {
+            if (im->gdes[ii].gf != GF_DEF) 
+                continue;
+            if ((strcmp(im->gdes[i].rrd, im->gdes[ii].rrd) == 0)
+                        && (im->gdes[i].cf    == im->gdes[ii].cf)
+                        && (im->gdes[i].cf_reduce == im->gdes[ii].cf_reduce)
+                        && (im->gdes[i].start_orig == im->gdes[ii].start_orig)
+                        && (im->gdes[i].end_orig   == im->gdes[ii].end_orig)
+                        && (im->gdes[i].step_orig  == im->gdes[ii].step_orig)) {
+                /* OK, the data is already there.
+                ** Just copy the header portion
+                */
+                im->gdes[i].start = im->gdes[ii].start;
+                im->gdes[i].end = im->gdes[ii].end;
+                im->gdes[i].step = im->gdes[ii].step;
+                im->gdes[i].ds_cnt = im->gdes[ii].ds_cnt;
+                im->gdes[i].ds_namv = im->gdes[ii].ds_namv;                
+                im->gdes[i].data = im->gdes[ii].data;
+                im->gdes[i].data_first = 0;
+                skip=1;
+            }
+            if (skip) 
+                break;
+        }
+        if (! skip) {
+            unsigned long  ft_step = im->gdes[i].step ; /* ft_step will record what we got from fetch */
+            
+            if((rrd_fetch_fn(im->gdes[i].rrd,
+                             im->gdes[i].cf,
+                             &im->gdes[i].start,
+                             &im->gdes[i].end,
+                             &ft_step,
+                             &im->gdes[i].ds_cnt,
+                             &im->gdes[i].ds_namv,
+                             &im->gdes[i].data)) == -1){                
+                return -1;
+            }
+            im->gdes[i].data_first = 1;            
+        
+            if (ft_step < im->gdes[i].step) {
+                reduce_data(im->gdes[i].cf_reduce,
+                            ft_step,
+                            &im->gdes[i].start,
+                            &im->gdes[i].end,
+                            &im->gdes[i].step,
+                            &im->gdes[i].ds_cnt,
+                            &im->gdes[i].data);
+            } else {
+                im->gdes[i].step = ft_step;
+            }
+        }
+        
         /* lets see if the required data source is really there */
-       for(ii=0;ii<(int)im->gdes[i].ds_cnt;ii++){
-           if(strcmp(im->gdes[i].ds_namv[ii],im->gdes[i].ds_nam) == 0){
-               im->gdes[i].ds=ii; }
-       }
-       if (im->gdes[i].ds== -1){
-           rrd_set_error("No DS called '%s' in '%s'",
-                         im->gdes[i].ds_nam,im->gdes[i].rrd);
-           return -1; 
-       }
-       
+        for(ii=0;ii<(int)im->gdes[i].ds_cnt;ii++){
+            if(strcmp(im->gdes[i].ds_namv[ii],im->gdes[i].ds_nam) == 0){
+                im->gdes[i].ds=ii; }
+        }
+        if (im->gdes[i].ds== -1){
+            rrd_set_error("No DS called '%s' in '%s'",
+                          im->gdes[i].ds_nam,im->gdes[i].rrd);
+            return -1; 
+        }
+        
     }
     return 0;
 }
@@ -777,13 +787,13 @@ long
 find_var(image_desc_t *im, char *key){
     long ii;
     for(ii=0;ii<im->gdes_c-1;ii++){
-       if((im->gdes[ii].gf == GF_DEF 
-           || im->gdes[ii].gf == GF_VDEF
-           || im->gdes[ii].gf == GF_CDEF) 
-          && (strcmp(im->gdes[ii].vname,key) == 0)){
-           return ii; 
-       }          
-    }              
+        if((im->gdes[ii].gf == GF_DEF 
+            || im->gdes[ii].gf == GF_VDEF
+            || im->gdes[ii].gf == GF_CDEF) 
+           && (strcmp(im->gdes[ii].vname,key) == 0)){
+            return ii; 
+        }           
+    }                        
     return -1;
 }
 
@@ -794,11 +804,11 @@ lcd(long *num){
     long rest;
     int i;
     for (i=0;num[i+1]!=0;i++){
-       do { 
-           rest=num[i] % num[i+1];
-           num[i]=num[i+1]; num[i+1]=rest;
-       } while (rest!=0);
-       num[i+1] = num[i];
+        do { 
+            rest=num[i] % num[i+1];
+            num[i]=num[i+1]; num[i+1]=rest;
+        } while (rest!=0);
+        num[i+1] = num[i];
     }
 /*    return i==0?num[i]:num[i-1]; */
       return num[i];
@@ -818,176 +828,180 @@ data_calc( image_desc_t *im){
     rpnstack_init(&rpnstack);
 
     for (gdi=0;gdi<im->gdes_c;gdi++){
-       /* Look for GF_VDEF and GF_CDEF in the same loop,
-        * so CDEFs can use VDEFs and vice versa
-        */
-       switch (im->gdes[gdi].gf) {
-           case GF_XPORT:
-             break;
-           case GF_SHIFT: {
-               graph_desc_t    *vdp = &im->gdes[im->gdes[gdi].vidx];
-               
-               /* remove current shift */
-               vdp->start -= vdp->shift;
-               vdp->end -= vdp->shift;
-               
-               /* vdef */
-               if (im->gdes[gdi].shidx >= 0) 
-                       vdp->shift = im->gdes[im->gdes[gdi].shidx].vf.val;
-               /* constant */
-               else
-                       vdp->shift = im->gdes[gdi].shval;
-
-               /* normalize shift to multiple of consolidated step */
-               vdp->shift = (vdp->shift / (long)vdp->step) * (long)vdp->step;
-
-               /* apply shift */
-               vdp->start += vdp->shift;
-               vdp->end += vdp->shift;
-               break;
-           }
-           case GF_VDEF:
-               /* A VDEF has no DS.  This also signals other parts
-                * of rrdtool that this is a VDEF value, not a CDEF.
-                */
-               im->gdes[gdi].ds_cnt = 0;
-               if (vdef_calc(im,gdi)) {
-                   rrd_set_error("Error processing VDEF '%s'"
-                       ,im->gdes[gdi].vname
-                       );
-                   rpnstack_free(&rpnstack);
-                   return -1;
-               }
-               break;
-           case GF_CDEF:
-               im->gdes[gdi].ds_cnt = 1;
-               im->gdes[gdi].ds = 0;
-               im->gdes[gdi].data_first = 1;
-               im->gdes[gdi].start = 0;
-               im->gdes[gdi].end = 0;
-               steparray=NULL;
-               stepcnt = 0;
-               dataidx=-1;
-
-               /* Find the variables in the expression.
-                * - VDEF variables are substituted by their values
-                *   and the opcode is changed into OP_NUMBER.
-                * - CDEF variables are analized for their step size,
-                *   the lowest common denominator of all the step
-                *   sizes of the data sources involved is calculated
-                *   and the resulting number is the step size for the
-                *   resulting data source.
-                */
-               for(rpi=0;im->gdes[gdi].rpnp[rpi].op != OP_END;rpi++){
-               if(im->gdes[gdi].rpnp[rpi].op == OP_VARIABLE ||
-                  im->gdes[gdi].rpnp[rpi].op == OP_PREV_OTHER){
-                       long ptr = im->gdes[gdi].rpnp[rpi].ptr;
-                       if (im->gdes[ptr].ds_cnt == 0) {
+        /* Look for GF_VDEF and GF_CDEF in the same loop,
+         * so CDEFs can use VDEFs and vice versa
+         */
+        switch (im->gdes[gdi].gf) {
+            case GF_XPORT:
+              break;
+            case GF_SHIFT: {
+                graph_desc_t        *vdp = &im->gdes[im->gdes[gdi].vidx];
+                
+                /* remove current shift */
+                vdp->start -= vdp->shift;
+                vdp->end -= vdp->shift;
+                
+                /* vdef */
+                if (im->gdes[gdi].shidx >= 0) 
+                        vdp->shift = im->gdes[im->gdes[gdi].shidx].vf.val;
+                /* constant */
+                else
+                        vdp->shift = im->gdes[gdi].shval;
+
+                /* normalize shift to multiple of consolidated step */
+                vdp->shift = (vdp->shift / (long)vdp->step) * (long)vdp->step;
+
+                /* apply shift */
+                vdp->start += vdp->shift;
+                vdp->end += vdp->shift;
+                break;
+            }
+            case GF_VDEF:
+                /* A VDEF has no DS.  This also signals other parts
+                 * of rrdtool that this is a VDEF value, not a CDEF.
+                 */
+                im->gdes[gdi].ds_cnt = 0;
+                if (vdef_calc(im,gdi)) {
+                    rrd_set_error("Error processing VDEF '%s'"
+                        ,im->gdes[gdi].vname
+                        );
+                    rpnstack_free(&rpnstack);
+                    return -1;
+                }
+                break;
+            case GF_CDEF:
+                im->gdes[gdi].ds_cnt = 1;
+                im->gdes[gdi].ds = 0;
+                im->gdes[gdi].data_first = 1;
+                im->gdes[gdi].start = 0;
+                im->gdes[gdi].end = 0;
+                steparray=NULL;
+                stepcnt = 0;
+                dataidx=-1;
+
+                /* Find the variables in the expression.
+                 * - VDEF variables are substituted by their values
+                 *   and the opcode is changed into OP_NUMBER.
+                 * - CDEF variables are analized for their step size,
+                 *   the lowest common denominator of all the step
+                 *   sizes of the data sources involved is calculated
+                 *   and the resulting number is the step size for the
+                 *   resulting data source.
+                 */
+                for(rpi=0;im->gdes[gdi].rpnp[rpi].op != OP_END;rpi++){
+                    if(im->gdes[gdi].rpnp[rpi].op == OP_VARIABLE  ||
+                        im->gdes[gdi].rpnp[rpi].op == OP_PREV_OTHER){
+                        long ptr = im->gdes[gdi].rpnp[rpi].ptr;
+                        if (im->gdes[ptr].ds_cnt == 0) { /* this is a VDEF data source */
 #if 0
-                       printf("DEBUG: inside CDEF '%s' processing VDEF '%s'\n",
-       im->gdes[gdi].vname,
-       im->gdes[ptr].vname);
-                       printf("DEBUG: value from vdef is %f\n",im->gdes[ptr].vf.val);
+                            printf("DEBUG: inside CDEF '%s' processing VDEF '%s'\n",
+                               im->gdes[gdi].vname,
+                               im->gdes[ptr].vname);
+                            printf("DEBUG: value from vdef is %f\n",im->gdes[ptr].vf.val);
 #endif
-                           im->gdes[gdi].rpnp[rpi].val = im->gdes[ptr].vf.val;
-                           im->gdes[gdi].rpnp[rpi].op  = OP_NUMBER;
-                       } else {
-                       if ((steparray =
-                                rrd_realloc(steparray,
-                                                        (++stepcnt+1)*sizeof(*steparray)))==NULL){
-                               rrd_set_error("realloc steparray");
-                               rpnstack_free(&rpnstack);
-                               return -1;
-                           };
-
-                           steparray[stepcnt-1] = im->gdes[ptr].step;
-
-                           /* adjust start and end of cdef (gdi) so
-                            * that it runs from the latest start point
-                            * to the earliest endpoint of any of the
-                            * rras involved (ptr)
-                            */
-                           if(im->gdes[gdi].start < im->gdes[ptr].start)
-                               im->gdes[gdi].start = im->gdes[ptr].start;
-
-                           if(im->gdes[gdi].end == 0 ||
-                                       im->gdes[gdi].end > im->gdes[ptr].end)
-                               im->gdes[gdi].end = im->gdes[ptr].end;
-               
-                           /* store pointer to the first element of
-                            * the rra providing data for variable,
-                            * further save step size and data source
-                            * count of this rra
-                            */ 
-                            im->gdes[gdi].rpnp[rpi].data =  im->gdes[ptr].data + im->gdes[ptr].ds;
-                           im->gdes[gdi].rpnp[rpi].step = im->gdes[ptr].step;
-                           im->gdes[gdi].rpnp[rpi].ds_cnt = im->gdes[ptr].ds_cnt;
-
-                           /* backoff the *.data ptr; this is done so
-                            * rpncalc() function doesn't have to treat
-                            * the first case differently
-                            */
-                       } /* if ds_cnt != 0 */
-                   } /* if OP_VARIABLE */
-               } /* loop through all rpi */
+                            im->gdes[gdi].rpnp[rpi].val = im->gdes[ptr].vf.val;
+                            im->gdes[gdi].rpnp[rpi].op  = OP_NUMBER;
+                        } else { /* normal variables and PREF(variables) */
+
+                            /* add one entry to the array that keeps track of the step sizes of the
+                             * data sources going into the CDEF. */
+                            if ((steparray =
+                                 rrd_realloc(steparray,
+                                                         (++stepcnt+1)*sizeof(*steparray)))==NULL){
+                                  rrd_set_error("realloc steparray");
+                                  rpnstack_free(&rpnstack);
+                                 return -1;
+                            };
+
+                            steparray[stepcnt-1] = im->gdes[ptr].step;
+
+                            /* adjust start and end of cdef (gdi) so
+                             * that it runs from the latest start point
+                             * to the earliest endpoint of any of the
+                             * rras involved (ptr)
+                             */
+
+                            if(im->gdes[gdi].start < im->gdes[ptr].start)
+                                im->gdes[gdi].start = im->gdes[ptr].start;
+
+                            if(im->gdes[gdi].end == 0 ||
+                                        im->gdes[gdi].end > im->gdes[ptr].end)
+                                im->gdes[gdi].end = im->gdes[ptr].end;
+                
+                            /* store pointer to the first element of
+                             * the rra providing data for variable,
+                             * further save step size and data source
+                             * count of this rra
+                             */ 
+                            im->gdes[gdi].rpnp[rpi].data   = im->gdes[ptr].data + im->gdes[ptr].ds;
+                            im->gdes[gdi].rpnp[rpi].step   = im->gdes[ptr].step;
+                            im->gdes[gdi].rpnp[rpi].ds_cnt = im->gdes[ptr].ds_cnt;
+
+                            /* backoff the *.data ptr; this is done so
+                             * rpncalc() function doesn't have to treat
+                             * the first case differently
+                             */
+                        } /* if ds_cnt != 0 */
+                    } /* if OP_VARIABLE */
+                } /* loop through all rpi */
 
                 /* move the data pointers to the correct period */
                 for(rpi=0;im->gdes[gdi].rpnp[rpi].op != OP_END;rpi++){
-               if(im->gdes[gdi].rpnp[rpi].op == OP_VARIABLE ||
-                  im->gdes[gdi].rpnp[rpi].op == OP_PREV_OTHER){
-                        long ptr = im->gdes[gdi].rpnp[rpi].ptr;
-                       long diff = im->gdes[gdi].start - im->gdes[ptr].start;
+                    if(im->gdes[gdi].rpnp[rpi].op == OP_VARIABLE ||
+                        im->gdes[gdi].rpnp[rpi].op == OP_PREV_OTHER){
+                        long ptr  = im->gdes[gdi].rpnp[rpi].ptr;
+                        long diff = im->gdes[gdi].start - im->gdes[ptr].start;
 
                         if(diff > 0)
-                           im->gdes[gdi].rpnp[rpi].data += (diff / im->gdes[ptr].step) * im->gdes[ptr].ds_cnt;
+                            im->gdes[gdi].rpnp[rpi].data += (diff / im->gdes[ptr].step) * im->gdes[ptr].ds_cnt;
                      }
                 }
 
-               if(steparray == NULL){
-                   rrd_set_error("rpn expressions without DEF"
-                               " or CDEF variables are not supported");
-                   rpnstack_free(&rpnstack);
-                   return -1;    
-               }
-               steparray[stepcnt]=0;
-               /* Now find the resulting step.  All steps in all
-                * used RRAs have to be visited
-                */
-               im->gdes[gdi].step = lcd(steparray);
-               free(steparray);
-               if((im->gdes[gdi].data = malloc((
-                               (im->gdes[gdi].end-im->gdes[gdi].start) 
-                                   / im->gdes[gdi].step)
-                                   * sizeof(double)))==NULL){
-                   rrd_set_error("malloc im->gdes[gdi].data");
-                   rpnstack_free(&rpnstack);
-                   return -1;
-               }
-       
-               /* Step through the new cdef results array and
-                * calculate the values
-                */
-               for (now = im->gdes[gdi].start + im->gdes[gdi].step;
-                               now<=im->gdes[gdi].end;
-                               now += im->gdes[gdi].step)
-               {
-                   rpnp_t  *rpnp = im -> gdes[gdi].rpnp;
-
-                   /* 3rd arg of rpn_calc is for OP_VARIABLE lookups;
-                    * in this case we are advancing by timesteps;
-                    * we use the fact that time_t is a synonym for long
-                    */
-                   if (rpn_calc(rpnp,&rpnstack,(long) now, 
-                               im->gdes[gdi].data,++dataidx) == -1) {
-                       /* rpn_calc sets the error string */
-                       rpnstack_free(&rpnstack); 
-                       return -1;
-                   } 
-               } /* enumerate over time steps within a CDEF */
-               break;
-           default:
-               continue;
-       }
+                if(steparray == NULL){
+                    rrd_set_error("rpn expressions without DEF"
+                                " or CDEF variables are not supported");
+                    rpnstack_free(&rpnstack);
+                    return -1;    
+                }
+                steparray[stepcnt]=0;
+                /* Now find the resulting step.  All steps in all
+                 * used RRAs have to be visited
+                 */
+                im->gdes[gdi].step = lcd(steparray);
+                free(steparray);
+                if((im->gdes[gdi].data = malloc((
+                                (im->gdes[gdi].end-im->gdes[gdi].start) 
+                                    / im->gdes[gdi].step)
+                                    * sizeof(double)))==NULL){
+                    rrd_set_error("malloc im->gdes[gdi].data");
+                    rpnstack_free(&rpnstack);
+                    return -1;
+                }
+        
+                /* Step through the new cdef results array and
+                 * calculate the values
+                 */
+                for (now = im->gdes[gdi].start + im->gdes[gdi].step;
+                                now<=im->gdes[gdi].end;
+                                now += im->gdes[gdi].step)
+                {
+                    rpnp_t  *rpnp = im -> gdes[gdi].rpnp;
+
+                    /* 3rd arg of rpn_calc is for OP_VARIABLE lookups;
+                     * in this case we are advancing by timesteps;
+                     * we use the fact that time_t is a synonym for long
+                     */
+                    if (rpn_calc(rpnp,&rpnstack,(long) now, 
+                                im->gdes[gdi].data,++dataidx) == -1) {
+                        /* rpn_calc sets the error string */
+                        rpnstack_free(&rpnstack); 
+                        return -1;
+                    
+                } /* enumerate over time steps within a CDEF */
+                break;
+            default:
+                continue;
+        }
     } /* enumerate over CDEFs */
     rpnstack_free(&rpnstack);
     return 0;
@@ -998,8 +1012,8 @@ int
 data_proc( image_desc_t *im ){
     long i,ii;
     double pixstep = (double)(im->end-im->start)
-       /(double)im->xsize; /* how much time 
-                              passes in one pixel */
+        /(double)im->xsize; /* how much time 
+                               passes in one pixel */
     double paintval;
     double minval=DNAN,maxval=DNAN;
     
@@ -1007,96 +1021,109 @@ data_proc( image_desc_t *im ){
 
     /* memory for the processed data */
     for(i=0;i<im->gdes_c;i++) {
-       if((im->gdes[i].gf==GF_LINE) ||
-               (im->gdes[i].gf==GF_AREA) ||
-               (im->gdes[i].gf==GF_TICK) ||
-               (im->gdes[i].gf==GF_STACK)) {
-           if((im->gdes[i].p_data = malloc((im->xsize +1)
-                                       * sizeof(rrd_value_t)))==NULL){
-               rrd_set_error("malloc data_proc");
-               return -1;
-           }
-       }
+        if((im->gdes[i].gf==GF_LINE) ||
+                (im->gdes[i].gf==GF_AREA) ||
+                (im->gdes[i].gf==GF_TICK)) {
+            if((im->gdes[i].p_data = malloc((im->xsize +1)
+                                        * sizeof(rrd_value_t)))==NULL){
+                rrd_set_error("malloc data_proc");
+                return -1;
+            }
+        }
     }
 
-    for (i=0;i<im->xsize;i++) {        /* for each pixel */
-       long vidx;
-       gr_time = im->start+pixstep*i; /* time of the current step */
-       paintval=0.0;
-       
-       for (ii=0;ii<im->gdes_c;ii++) {
-           double value;
-           switch (im->gdes[ii].gf) {
-               case GF_LINE:
-               case GF_AREA:
-               case GF_TICK:
-                   if (!im->gdes[ii].stack)
-                       paintval = 0.0;
-               case GF_STACK:
-                   value = im->gdes[ii].yrule;
-                   if (isnan(value) || (im->gdes[ii].gf == GF_TICK)) {
-                       /* The time of the data doesn't necessarily match
-                       ** the time of the graph. Beware.
-                       */
-                       vidx = im->gdes[ii].vidx;
-                       if (im->gdes[vidx].gf == GF_VDEF) {
-                           value = im->gdes[vidx].vf.val;
-                       } else if (((long int)gr_time >= (long int)im->gdes[vidx].start) &&
-                                  ((long int)gr_time <= (long int)im->gdes[vidx].end) ) {
-                           value = im->gdes[vidx].data[
-                               (unsigned long) floor(
-                                   (double)(gr_time - im->gdes[vidx].start)
-                                               / im->gdes[vidx].step)
-                               * im->gdes[vidx].ds_cnt
-                               + im->gdes[vidx].ds
-                           ];
-                       } else {
-                           value = DNAN;
-                       }
-                   };
-
-                   if (! isnan(value)) {
-                       paintval += value;
-                       im->gdes[ii].p_data[i] = paintval;
-                       /* GF_TICK: the data values are not
-                       ** relevant for min and max
-                       */
-                       if (finite(paintval) && im->gdes[ii].gf != GF_TICK ) {
-                           if (isnan(minval) || paintval <  minval)
-                               minval = paintval;
-                           if (isnan(maxval) || paintval >  maxval)
-                               maxval = paintval;
-                       }
-                   } else {
-                       im->gdes[ii].p_data[i] = DNAN;
-                   }
-                   break;
-               default:
-                   break;
-           }
-       }
+    for (i=0;i<im->xsize;i++) {        /* for each pixel */
+        long vidx;
+        gr_time = im->start+pixstep*i; /* time of the current step */
+        paintval=0.0;
+        
+        for (ii=0;ii<im->gdes_c;ii++) {
+            double value;
+            switch (im->gdes[ii].gf) {
+                case GF_LINE:
+                case GF_AREA:
+                case GF_TICK:
+                    if (!im->gdes[ii].stack)
+                        paintval = 0.0;
+                    value = im->gdes[ii].yrule;
+                    if (isnan(value) || (im->gdes[ii].gf == GF_TICK)) {
+                        /* The time of the data doesn't necessarily match
+                        ** the time of the graph. Beware.
+                        */
+                        vidx = im->gdes[ii].vidx;
+                        if (im->gdes[vidx].gf == GF_VDEF) {
+                            value = im->gdes[vidx].vf.val;
+                        } else if (((long int)gr_time >= (long int)im->gdes[vidx].start) &&
+                                   ((long int)gr_time <= (long int)im->gdes[vidx].end) ) {
+                            value = im->gdes[vidx].data[
+                                (unsigned long) floor(
+                                    (double)(gr_time - im->gdes[vidx].start)
+                                                / im->gdes[vidx].step)
+                                * im->gdes[vidx].ds_cnt
+                                + im->gdes[vidx].ds
+                            ];
+                        } else {
+                            value = DNAN;
+                        }
+                    };
+
+                    if (! isnan(value)) {
+                        paintval += value;
+                        im->gdes[ii].p_data[i] = paintval;
+                        /* GF_TICK: the data values are not
+                        ** relevant for min and max
+                        */
+                        if (finite(paintval) && im->gdes[ii].gf != GF_TICK ) {
+                            if ((isnan(minval) || paintval <  minval ) &&
+                              ! (im->logarithmic && paintval <= 0.0)) 
+                                        minval = paintval;
+                            if (isnan(maxval) || paintval >  maxval)
+                                maxval = paintval;
+                        }
+                    } else {
+                        im->gdes[ii].p_data[i] = DNAN;
+                    }
+                    break;
+                case GF_STACK:
+                    rrd_set_error("STACK should already be turned into LINE or AREA here");
+                    return -1;
+                    break;
+                default:
+                    break;
+            }
+        }
     }
 
     /* if min or max have not been asigned a value this is because
        there was no data in the graph ... this is not good ...
        lets set these to dummy values then ... */
 
-    if (isnan(minval)) minval = 0.0;
-    if (isnan(maxval)) maxval = 1.0;
+    if (im->logarithmic) {
+        if (isnan(minval)) minval = 0.2;
+        if (isnan(maxval)) maxval = 5.1;
+    }
+    else {
+        if (isnan(minval)) minval = 0.0;
+        if (isnan(maxval)) maxval = 1.0;
+    }
     
     /* adjust min and max values */
     if (isnan(im->minval) 
-       /* don't adjust low-end with log scale */
-       || ((!im->logarithmic && !im->rigid) && im->minval > minval)
-       )
-       im->minval = minval;
+        /* don't adjust low-end with log scale */ /* why not? */
+        || ((!im->rigid) && im->minval > minval)
+        ) {
+        if (im->logarithmic)
+            im->minval = minval * 0.5;
+        else
+            im->minval = minval;
+    }
     if (isnan(im->maxval) 
-       || (!im->rigid && im->maxval < maxval)
-       ) {
-       if (im->logarithmic)
-           im->maxval = maxval * 1.1;
-       else
-           im->maxval = maxval;
+        || (!im->rigid && im->maxval < maxval)
+        ) {
+        if (im->logarithmic)
+            im->maxval = maxval * 2.0;
+        else
+            im->maxval = maxval;
     }
     /* make sure min is smaller than max */
     if (im->minval > im->maxval) {
@@ -1105,14 +1132,14 @@ data_proc( image_desc_t *im ){
                       
     /* make sure min and max are not equal */
     if (im->minval == im->maxval) {
-       im->maxval *= 1.01; 
-       if (! im->logarithmic) {
-           im->minval *= 0.99;
-       }
-       /* make sure min and max are not both zero */
-       if (im->maxval == 0.0) {
-           im->maxval = 1.0;
-       }
+        im->maxval *= 1.01; 
+        if (! im->logarithmic) {
+            im->minval *= 0.99;
+        }
+        /* make sure min and max are not both zero */
+        if (im->maxval == 0.0) {
+            im->maxval = 1.0;
+        }
     }
     return 0;
 }
@@ -1132,43 +1159,43 @@ find_first_time(
     localtime_r(&start, &tm);
     switch(baseint){
     case TMT_SECOND:
-       tm.tm_sec -= tm.tm_sec % basestep; break;
+        tm.tm_sec -= tm.tm_sec % basestep; break;
     case TMT_MINUTE: 
-       tm.tm_sec=0;
-       tm.tm_min -= tm.tm_min % basestep; 
-       break;
+        tm.tm_sec=0;
+        tm.tm_min -= tm.tm_min % basestep; 
+        break;
     case TMT_HOUR:
-       tm.tm_sec=0;
-       tm.tm_min = 0;
-       tm.tm_hour -= tm.tm_hour % basestep; break;
+        tm.tm_sec=0;
+        tm.tm_min = 0;
+        tm.tm_hour -= tm.tm_hour % basestep; break;
     case TMT_DAY:
-       /* we do NOT look at the basestep for this ... */
-       tm.tm_sec=0;
-       tm.tm_min = 0;
-       tm.tm_hour = 0; break;
+        /* we do NOT look at the basestep for this ... */
+        tm.tm_sec=0;
+        tm.tm_min = 0;
+        tm.tm_hour = 0; break;
     case TMT_WEEK:
-       /* we do NOT look at the basestep for this ... */
-       tm.tm_sec=0;
-       tm.tm_min = 0;
-       tm.tm_hour = 0;
-       tm.tm_mday -= tm.tm_wday -1;    /* -1 because we want the monday */
-       if (tm.tm_wday==0) tm.tm_mday -= 7; /* we want the *previous* monday */
-       break;
+        /* we do NOT look at the basestep for this ... */
+        tm.tm_sec=0;
+        tm.tm_min = 0;
+        tm.tm_hour = 0;
+        tm.tm_mday -= tm.tm_wday -1;        /* -1 because we want the monday */
+        if (tm.tm_wday==0) tm.tm_mday -= 7; /* we want the *previous* monday */
+        break;
     case TMT_MONTH:
-       tm.tm_sec=0;
-       tm.tm_min = 0;
-       tm.tm_hour = 0;
-       tm.tm_mday = 1;
-       tm.tm_mon -= tm.tm_mon % basestep; break;
+        tm.tm_sec=0;
+        tm.tm_min = 0;
+        tm.tm_hour = 0;
+        tm.tm_mday = 1;
+        tm.tm_mon -= tm.tm_mon % basestep; break;
 
     case TMT_YEAR:
-       tm.tm_sec=0;
-       tm.tm_min = 0;
-       tm.tm_hour = 0;
-       tm.tm_mday = 1;
-       tm.tm_mon = 0;
-       tm.tm_year -= (tm.tm_year+1900) % basestep;
-       
+        tm.tm_sec=0;
+        tm.tm_min = 0;
+        tm.tm_hour = 0;
+        tm.tm_mday = 1;
+        tm.tm_mon = 0;
+        tm.tm_year -= (tm.tm_year+1900) % basestep;
+        
     }
     return mktime(&tm);
 }
@@ -1184,27 +1211,27 @@ find_next_time(
     time_t madetime;
     localtime_r(&current, &tm);
     do {
-       switch(baseint){
-       case TMT_SECOND:
-           tm.tm_sec += basestep; break;
-       case TMT_MINUTE: 
-           tm.tm_min += basestep; break;
-       case TMT_HOUR:
-           tm.tm_hour += basestep; break;
-       case TMT_DAY:
-           tm.tm_mday += basestep; break;
-       case TMT_WEEK:
-           tm.tm_mday += 7*basestep; break;
-       case TMT_MONTH:
-           tm.tm_mon += basestep; break;
-       case TMT_YEAR:
-           tm.tm_year += basestep;     
-       }
-       madetime = mktime(&tm);
+        switch(baseint){
+        case TMT_SECOND:
+            tm.tm_sec += basestep; break;
+        case TMT_MINUTE: 
+            tm.tm_min += basestep; break;
+        case TMT_HOUR:
+            tm.tm_hour += basestep; break;
+        case TMT_DAY:
+            tm.tm_mday += basestep; break;
+        case TMT_WEEK:
+            tm.tm_mday += 7*basestep; break;
+        case TMT_MONTH:
+            tm.tm_mon += basestep; break;
+        case TMT_YEAR:
+            tm.tm_year += basestep;        
+        }
+        madetime = mktime(&tm);
     } while (madetime == -1); /* this is necessary to skip impssible times
-                                like the daylight saving time skips */
+                                 like the daylight saving time skips */
     return madetime;
-         
+          
 }
 
 
@@ -1215,155 +1242,166 @@ print_calc(image_desc_t *im, char ***prdata)
 {
     long i,ii,validsteps;
     double printval;
-    time_t printtime;
+    struct tm tmvdef;
     int graphelement = 0;
     long vidx;
-    int max_ii;        
+    int max_ii;        
     double magfact = -1;
     char *si_symb = "";
     char *percent_s;
     int prlines = 1;
+    /* wow initializing tmvdef is quite a task :-) */
+    time_t now = time(NULL);
+    localtime_r(&now,&tmvdef);
     if (im->imginfo) prlines++;
     for(i=0;i<im->gdes_c;i++){
-       switch(im->gdes[i].gf){
-       case GF_PRINT:
-           prlines++;
-           if(((*prdata) = rrd_realloc((*prdata),prlines*sizeof(char *)))==NULL){
-               rrd_set_error("realloc prdata");
-               return 0;
-           }
-       case GF_GPRINT:
-           /* PRINT and GPRINT can now print VDEF generated values.
-            * There's no need to do any calculations on them as these
-            * calculations were already made.
-            */
-           vidx = im->gdes[i].vidx;
-           if (im->gdes[vidx].gf==GF_VDEF) { /* simply use vals */
-               printval = im->gdes[vidx].vf.val;
-               printtime = im->gdes[vidx].vf.when;
-           } else { /* need to calculate max,min,avg etcetera */
-               max_ii =((im->gdes[vidx].end 
-                       - im->gdes[vidx].start)
-                       / im->gdes[vidx].step
-                       * im->gdes[vidx].ds_cnt);
-               printval = DNAN;
-               validsteps = 0;
-               for(    ii=im->gdes[vidx].ds;
-                       ii < max_ii;
-                       ii+=im->gdes[vidx].ds_cnt){
-                   if (! finite(im->gdes[vidx].data[ii]))
-                       continue;
-                   if (isnan(printval)){
-                       printval = im->gdes[vidx].data[ii];
-                       validsteps++;
-                       continue;
-                   }
-
-                   switch (im->gdes[i].cf){
-                       case CF_HWPREDICT:
-                       case CF_DEVPREDICT:
-                       case CF_DEVSEASONAL:
-                       case CF_SEASONAL:
-                       case CF_AVERAGE:
-                           validsteps++;
-                           printval += im->gdes[vidx].data[ii];
-                           break;
-                       case CF_MINIMUM:
-                           printval = min( printval, im->gdes[vidx].data[ii]);
-                           break;
-                       case CF_FAILURES:
-                       case CF_MAXIMUM:
-                           printval = max( printval, im->gdes[vidx].data[ii]);
-                           break;
-                       case CF_LAST:
-                           printval = im->gdes[vidx].data[ii];
-                   }
-               }
-               if (im->gdes[i].cf==CF_AVERAGE || im->gdes[i].cf > CF_LAST) {
-                   if (validsteps > 1) {
-                       printval = (printval / validsteps);
-                   }
-               }
-           } /* prepare printval */
-
-           if (!strcmp(im->gdes[i].format,"%c")) { /* VDEF time print */
-               char ctime_buf[128]; /* PS: for ctime_r, must be >= 26 chars */
-               if (im->gdes[i].gf == GF_PRINT){
-                   (*prdata)[prlines-2] = malloc((FMT_LEG_LEN+2)*sizeof(char));
-                   sprintf((*prdata)[prlines-2],"%s (%lu)",
-                                       ctime_r(&printtime,ctime_buf),printtime);
-                   (*prdata)[prlines-1] = NULL;
-               } else {
-                   sprintf(im->gdes[i].legend,"%s (%lu)",
-                                       ctime_r(&printtime,ctime_buf),printtime);
-                   graphelement = 1;
-               }
-           } else {
-           if ((percent_s = strstr(im->gdes[i].format,"%S")) != NULL) {
-               /* Magfact is set to -1 upon entry to print_calc.  If it
-                * is still less than 0, then we need to run auto_scale.
-                * Otherwise, put the value into the correct units.  If
-                * the value is 0, then do not set the symbol or magnification
-                * so next the calculation will be performed again. */
-               if (magfact < 0.0) {
-                   auto_scale(im,&printval,&si_symb,&magfact);
-                   if (printval == 0.0)
-                       magfact = -1.0;
-               } else {
-                   printval /= magfact;
-               }
-               *(++percent_s) = 's';
-           } else if (strstr(im->gdes[i].format,"%s") != NULL) {
-               auto_scale(im,&printval,&si_symb,&magfact);
-           }
-
-           if (im->gdes[i].gf == GF_PRINT){
-               (*prdata)[prlines-2] = malloc((FMT_LEG_LEN+2)*sizeof(char));
-               (*prdata)[prlines-1] = NULL;
-               if (bad_format(im->gdes[i].format)) {
-                       rrd_set_error("bad format for PRINT in '%s'", im->gdes[i].format);
-                       return -1;
-               }
+            vidx = im->gdes[i].vidx;
+        switch(im->gdes[i].gf){
+        case GF_PRINT:
+            prlines++;
+            if(((*prdata) = rrd_realloc((*prdata),prlines*sizeof(char *)))==NULL){
+                rrd_set_error("realloc prdata");
+                return 0;
+            }
+        case GF_GPRINT:
+            /* PRINT and GPRINT can now print VDEF generated values.
+             * There's no need to do any calculations on them as these
+             * calculations were already made.
+             */
+            if (im->gdes[vidx].gf==GF_VDEF) { /* simply use vals */
+                printval = im->gdes[vidx].vf.val;
+                localtime_r(&im->gdes[vidx].vf.when,&tmvdef);
+            } else { /* need to calculate max,min,avg etcetera */
+                max_ii =((im->gdes[vidx].end 
+                        - im->gdes[vidx].start)
+                        / im->gdes[vidx].step
+                        * im->gdes[vidx].ds_cnt);
+                printval = DNAN;
+                validsteps = 0;
+                for(        ii=im->gdes[vidx].ds;
+                        ii < max_ii;
+                        ii+=im->gdes[vidx].ds_cnt){
+                    if (! finite(im->gdes[vidx].data[ii]))
+                        continue;
+                    if (isnan(printval)){
+                        printval = im->gdes[vidx].data[ii];
+                        validsteps++;
+                        continue;
+                    }
+
+                    switch (im->gdes[i].cf){
+                        case CF_HWPREDICT:
+                        case CF_DEVPREDICT:
+                        case CF_DEVSEASONAL:
+                        case CF_SEASONAL:
+                        case CF_AVERAGE:
+                            validsteps++;
+                            printval += im->gdes[vidx].data[ii];
+                            break;
+                        case CF_MINIMUM:
+                            printval = min( printval, im->gdes[vidx].data[ii]);
+                            break;
+                        case CF_FAILURES:
+                        case CF_MAXIMUM:
+                            printval = max( printval, im->gdes[vidx].data[ii]);
+                            break;
+                        case CF_LAST:
+                            printval = im->gdes[vidx].data[ii];
+                    }
+                }
+                if (im->gdes[i].cf==CF_AVERAGE || im->gdes[i].cf > CF_LAST) {
+                    if (validsteps > 1) {
+                        printval = (printval / validsteps);
+                    }
+                }
+            } /* prepare printval */
+
+            if ((percent_s = strstr(im->gdes[i].format,"%S")) != NULL) {
+                /* Magfact is set to -1 upon entry to print_calc.  If it
+                 * is still less than 0, then we need to run auto_scale.
+                 * Otherwise, put the value into the correct units.  If
+                 * the value is 0, then do not set the symbol or magnification
+                 * so next the calculation will be performed again. */
+                if (magfact < 0.0) {
+                    auto_scale(im,&printval,&si_symb,&magfact);
+                    if (printval == 0.0)
+                        magfact = -1.0;
+                } else {
+                    printval /= magfact;
+                }
+                *(++percent_s) = 's';
+            } else if (strstr(im->gdes[i].format,"%s") != NULL) {
+                auto_scale(im,&printval,&si_symb,&magfact);
+            }
+
+            if (im->gdes[i].gf == GF_PRINT){
+                (*prdata)[prlines-2] = malloc((FMT_LEG_LEN+2)*sizeof(char));
+                (*prdata)[prlines-1] = NULL;
+                if (im->gdes[i].strftm){
+                        strftime((*prdata)[prlines-2],FMT_LEG_LEN,im->gdes[i].format,&tmvdef);
+                } else {
+                     if (bad_format(im->gdes[i].format)) {
+                          rrd_set_error("bad format for PRINT in '%s'", im->gdes[i].format);
+                        return -1;
+                  }
+
 #ifdef HAVE_SNPRINTF
-               snprintf((*prdata)[prlines-2],FMT_LEG_LEN,im->gdes[i].format,printval,si_symb);
+                  snprintf((*prdata)[prlines-2],FMT_LEG_LEN,im->gdes[i].format,printval,si_symb);
 #else
-               sprintf((*prdata)[prlines-2],im->gdes[i].format,printval,si_symb);
+                  sprintf((*prdata)[prlines-2],im->gdes[i].format,printval,si_symb);
 #endif
-           } else {
-               /* GF_GPRINT */
+               }
+             } else {
+                /* GF_GPRINT */
 
-               if (bad_format(im->gdes[i].format)) {
-                       rrd_set_error("bad format for GPRINT in '%s'", im->gdes[i].format);
-                       return -1;
-               }
+                if (im->gdes[i].strftm){
+                        strftime(im->gdes[i].legend,FMT_LEG_LEN,im->gdes[i].format,&tmvdef);
+                } else {
+                    if (bad_format(im->gdes[i].format)) {
+                        rrd_set_error("bad format for GPRINT in '%s'", im->gdes[i].format);
+                        return -1;
+                  }
 #ifdef HAVE_SNPRINTF
-               snprintf(im->gdes[i].legend,FMT_LEG_LEN-2,im->gdes[i].format,printval,si_symb);
+                  snprintf(im->gdes[i].legend,FMT_LEG_LEN-2,im->gdes[i].format,printval,si_symb);
 #else
-               sprintf(im->gdes[i].legend,im->gdes[i].format,printval,si_symb);
+                  sprintf(im->gdes[i].legend,im->gdes[i].format,printval,si_symb);
 #endif
-               graphelement = 1;
-           }
-           }
-           break;
-       case GF_LINE:
-       case GF_AREA:
-       case GF_TICK:
-       case GF_STACK:
-       case GF_HRULE:
-       case GF_VRULE:
-           graphelement = 1;
-           break;
+                }
+                graphelement = 1;               
+            }            
+            break;
+        case GF_LINE:
+        case GF_AREA:
+        case GF_TICK:
+            graphelement = 1;
+            break;
+        case GF_HRULE:
+            if(isnan(im->gdes[i].yrule)) { /* we must set this here or the legend printer can not decide to print the legend */
+               im->gdes[i].yrule=im->gdes[vidx].vf.val;
+            };
+            graphelement = 1;
+            break;
+        case GF_VRULE:
+            if(im->gdes[i].xrule == 0) { /* again ... the legend printer needs it*/
+              im->gdes[i].xrule = im->gdes[vidx].vf.when;
+            };
+            graphelement = 1;
+            break;
         case GF_COMMENT:
-       case GF_DEF:
-       case GF_CDEF:       
-       case GF_VDEF:       
+        case GF_DEF:
+        case GF_CDEF:            
+        case GF_VDEF:            
 #ifdef WITH_PIECHART
-       case GF_PART:
+        case GF_PART:
 #endif
-       case GF_SHIFT:
-       case GF_XPORT:
-           break;
-       }
+        case GF_SHIFT:
+        case GF_XPORT:
+            break;
+        case GF_STACK:
+            rrd_set_error("STACK should already be turned into LINE or AREA here");
+            return -1;
+            break;
+        }
     }
     return graphelement;
 }
@@ -1379,6 +1417,7 @@ leg_place(image_desc_t *im)
     int   fill=0, fill_last;
     int   leg_c = 0;
     int   leg_x = border, leg_y = im->yimg;
+    int   leg_y_prev = im->yimg;
     int   leg_cc;
     int   glue = 0;
     int   i,ii, mark = 0;
@@ -1392,109 +1431,137 @@ leg_place(image_desc_t *im)
     }
 
     for(i=0;i<im->gdes_c;i++){
-       fill_last = fill;
+        fill_last = fill;
         
         /* hid legends for rules which are not displayed */
         
-       if(!(im->extra_flags & FORCE_RULES_LEGEND)) {
-               if (im->gdes[i].gf == GF_HRULE &&
-                   (im->gdes[i].yrule < im->minval || im->gdes[i].yrule > im->maxval))
-                   im->gdes[i].legend[0] = '\0';
-
-               if (im->gdes[i].gf == GF_VRULE &&
-                   (im->gdes[i].xrule < im->start || im->gdes[i].xrule > im->end))
-                   im->gdes[i].legend[0] = '\0';
-       }
+        if(!(im->extra_flags & FORCE_RULES_LEGEND)) {
+                if (im->gdes[i].gf == GF_HRULE &&
+                    (im->gdes[i].yrule < im->minval || im->gdes[i].yrule > im->maxval))
+                    im->gdes[i].legend[0] = '\0';
+
+                if (im->gdes[i].gf == GF_VRULE &&
+                    (im->gdes[i].xrule < im->start || im->gdes[i].xrule > im->end))
+                    im->gdes[i].legend[0] = '\0';
+        }
+
+        leg_cc = strlen(im->gdes[i].legend);
+        
+        /* is there a controle code ant the end of the legend string ? */ 
+        /* and it is not a tab \\t */
+        if (leg_cc >= 2 && im->gdes[i].legend[leg_cc-2] == '\\' && im->gdes[i].legend[leg_cc-1] != 't') {
+            prt_fctn = im->gdes[i].legend[leg_cc-1];
+            leg_cc -= 2;
+            im->gdes[i].legend[leg_cc] = '\0';
+        } else {
+            prt_fctn = '\0';
+        }
+        /* only valid control codes */
+        if (prt_fctn != 'l' && 
+            prt_fctn != 'n' && /* a synonym for l */
+            prt_fctn != 'r' &&
+            prt_fctn != 'j' &&
+            prt_fctn != 'c' &&
+            prt_fctn != 's' &&
+            prt_fctn != 't' &&
+            prt_fctn != '\0' &&
+            prt_fctn != 'g' ) {
+               free(legspace);
+               rrd_set_error("Unknown control code at the end of '%s\\%c'",im->gdes[i].legend,prt_fctn);
+                      return -1;
+
+        }
 
-       leg_cc = strlen(im->gdes[i].legend);
-       
-       /* is there a controle code ant the end of the legend string ? */ 
-       /* and it is not a tab \\t */
-       if (leg_cc >= 2 && im->gdes[i].legend[leg_cc-2] == '\\' && im->gdes[i].legend[leg_cc-1] != 't') {
-           prt_fctn = im->gdes[i].legend[leg_cc-1];
-           leg_cc -= 2;
-           im->gdes[i].legend[leg_cc] = '\0';
-       } else {
-           prt_fctn = '\0';
-       }
         /* remove exess space */
+        if ( prt_fctn == 'n' ){
+            prt_fctn='l';
+        }
+
         while (prt_fctn=='g' && 
-              leg_cc > 0 && 
-              im->gdes[i].legend[leg_cc-1]==' '){
-          leg_cc--;
-          im->gdes[i].legend[leg_cc]='\0';
-       }
-       if (leg_cc != 0 ){
-          legspace[i]=(prt_fctn=='g' ? 0 : interleg);
-          
-          if (fill > 0){ 
-              /* no interleg space if string ends in \g */
-              fill += legspace[i];
-           }
-          fill += gfx_get_text_width(im->canvas, fill+border,
-                                     im->text_prop[TEXT_PROP_LEGEND].font,
-                                     im->text_prop[TEXT_PROP_LEGEND].size,
-                                     im->tabwidth,
-                                     im->gdes[i].legend, 0);
-           leg_c++;
-       } else {
-          legspace[i]=0;
-       }
+               leg_cc > 0 && 
+               im->gdes[i].legend[leg_cc-1]==' '){
+           leg_cc--;
+           im->gdes[i].legend[leg_cc]='\0';
+        }
+        if (leg_cc != 0 ){
+           legspace[i]=(prt_fctn=='g' ? 0 : interleg);
+           
+           if (fill > 0){ 
+                /* no interleg space if string ends in \g */
+               fill += legspace[i];
+            }
+           fill += gfx_get_text_width(im->canvas, fill+border,
+                                      im->text_prop[TEXT_PROP_LEGEND].font,
+                                      im->text_prop[TEXT_PROP_LEGEND].size,
+                                      im->tabwidth,
+                                      im->gdes[i].legend, 0);
+            leg_c++;
+        } else {
+           legspace[i]=0;
+        }
         /* who said there was a special tag ... ?*/
-       if (prt_fctn=='g') {    
-          prt_fctn = '\0';
-       }
-       if (prt_fctn == '\0') {
-           if (i == im->gdes_c -1 ) prt_fctn ='l';
-           
-           /* is it time to place the legends ? */
-           if (fill > im->ximg - 2*border){
-               if (leg_c > 1) {
-                   /* go back one */
-                   i--; 
-                   fill = fill_last;
-                   leg_c--;
-                   prt_fctn = 'j';
-               } else {
-                   prt_fctn = 'l';
-               }
-               
-           }
-       }
+        if (prt_fctn=='g') {    
+           prt_fctn = '\0';
+        }
+        if (prt_fctn == '\0') {
+            if (i == im->gdes_c -1 ) prt_fctn ='l';
+            
+            /* is it time to place the legends ? */
+            if (fill > im->ximg - 2*border){
+                if (leg_c > 1) {
+                    /* go back one */
+                    i--; 
+                    fill = fill_last;
+                    leg_c--;
+                    prt_fctn = 'j';
+                } else {
+                    prt_fctn = 'l';
+                }
+                
+            }
+        }
 
 
-       if (prt_fctn != '\0'){  
-           leg_x = border;
-           if (leg_c >= 2 && prt_fctn == 'j') {
-               glue = (im->ximg - fill - 2* border) / (leg_c-1);
-           } else {
-               glue = 0;
-           }
-           if (prt_fctn =='c') leg_x =  (im->ximg - fill) / 2.0;
-           if (prt_fctn =='r') leg_x =  im->ximg - fill - border;
-
-           for(ii=mark;ii<=i;ii++){
-               if(im->gdes[ii].legend[0]=='\0')
-                   continue; /* skip empty legends */
-               im->gdes[ii].leg_x = leg_x;
-               im->gdes[ii].leg_y = leg_y;
-               leg_x += 
-                gfx_get_text_width(im->canvas, leg_x,
-                                     im->text_prop[TEXT_PROP_LEGEND].font,
-                                     im->text_prop[TEXT_PROP_LEGEND].size,
-                                     im->tabwidth,
-                                     im->gdes[ii].legend, 0) 
-                  + legspace[ii]
-                  + glue;
-           }                   
-           leg_y += im->text_prop[TEXT_PROP_LEGEND].size*1.7;
-           if (prt_fctn == 's') leg_y -=  im->text_prop[TEXT_PROP_LEGEND].size;           
-           fill = 0;
-           leg_c = 0;
-           mark = ii;
-       }          
-    }
-    im->yimg = leg_y;
+        if (prt_fctn != '\0'){        
+            leg_x = border;
+            if (leg_c >= 2 && prt_fctn == 'j') {
+                glue = (im->ximg - fill - 2* border) / (leg_c-1);
+            } else {
+                glue = 0;
+            }
+            if (prt_fctn =='c') leg_x =  (im->ximg - fill) / 2.0;
+            if (prt_fctn =='r') leg_x =  im->ximg - fill - border;
+
+            for(ii=mark;ii<=i;ii++){
+                if(im->gdes[ii].legend[0]=='\0')
+                    continue; /* skip empty legends */
+                im->gdes[ii].leg_x = leg_x;
+                im->gdes[ii].leg_y = leg_y;
+                leg_x += 
+                 gfx_get_text_width(im->canvas, leg_x,
+                                      im->text_prop[TEXT_PROP_LEGEND].font,
+                                      im->text_prop[TEXT_PROP_LEGEND].size,
+                                      im->tabwidth,
+                                      im->gdes[ii].legend, 0) 
+                   + legspace[ii]
+                   + glue;
+            }                        
+            leg_y_prev = leg_y;
+            /* only add y space if there was text on the line */
+            if (leg_x > border || prt_fctn == 's')            
+               leg_y += im->text_prop[TEXT_PROP_LEGEND].size*1.8;
+            if (prt_fctn == 's')
+               leg_y -=  im->text_prop[TEXT_PROP_LEGEND].size;           
+            fill = 0;
+            leg_c = 0;
+            mark = ii;
+        }           
+    }
+    im->yimg = leg_y_prev;
+    /* if we did place some legends we have to add vertical space */
+    if (leg_y != im->yimg){
+        im->yimg += im->text_prop[TEXT_PROP_LEGEND].size*1.8;
+    }
     free(legspace);
   }
   return 0;
@@ -1514,73 +1581,77 @@ calc_horizontal_grid(image_desc_t   *im)
     double   range;
     double   scaledrange;
     int      pixel,i;
-    int      gridind;
+    int      gridind=0;
     int      decimals, fractionals;
 
     im->ygrid_scale.labfact=2;
-    gridind=-1;
     range =  im->maxval - im->minval;
     scaledrange = range / im->magfact;
 
-       /* does the scale of this graph make it impossible to put lines
-          on it? If so, give up. */
-       if (isnan(scaledrange)) {
-               return 0;
-       }
+        /* does the scale of this graph make it impossible to put lines
+           on it? If so, give up. */
+        if (isnan(scaledrange)) {
+                return 0;
+        }
 
     /* find grid spaceing */
     pixel=1;
     if(isnan(im->ygridstep)){
-       if(im->extra_flags & ALTYGRID) {
-           /* find the value with max number of digits. Get number of digits */
-           decimals = ceil(log10(max(fabs(im->maxval), fabs(im->minval))));
-           if(decimals <= 0) /* everything is small. make place for zero */
-               decimals = 1;
-           
-           fractionals = floor(log10(range));
-           if(fractionals < 0) /* small amplitude. */
-               sprintf(im->ygrid_scale.labfmt, "%%%d.%df", decimals - fractionals + 1, -fractionals + 1);
-           else
-               sprintf(im->ygrid_scale.labfmt, "%%%d.1f", decimals + 1);
-           im->ygrid_scale.gridstep = pow((double)10, (double)fractionals);
-           if(im->ygrid_scale.gridstep == 0) /* range is one -> 0.1 is reasonable scale */
-               im->ygrid_scale.gridstep = 0.1;
-           /* should have at least 5 lines but no more then 15 */
-           if(range/im->ygrid_scale.gridstep < 5)
+        if(im->extra_flags & ALTYGRID) {
+            /* find the value with max number of digits. Get number of digits */
+            decimals = ceil(log10(max(fabs(im->maxval), fabs(im->minval))*im->viewfactor/im->magfact));
+            if(decimals <= 0) /* everything is small. make place for zero */
+                decimals = 1;
+            
+            im->ygrid_scale.gridstep = pow((double)10, floor(log10(range*im->viewfactor/im->magfact)))/im->viewfactor*im->magfact;
+            
+            if(im->ygrid_scale.gridstep == 0) /* range is one -> 0.1 is reasonable scale */
+                im->ygrid_scale.gridstep = 0.1;
+            /* should have at least 5 lines but no more then 15 */
+            if(range/im->ygrid_scale.gridstep < 5)
                 im->ygrid_scale.gridstep /= 10;
-           if(range/im->ygrid_scale.gridstep > 15)
+            if(range/im->ygrid_scale.gridstep > 15)
                 im->ygrid_scale.gridstep *= 10;
-           if(range/im->ygrid_scale.gridstep > 5) {
-               im->ygrid_scale.labfact = 1;
-               if(range/im->ygrid_scale.gridstep > 8)
-                   im->ygrid_scale.labfact = 2;
-           }
-           else {
-               im->ygrid_scale.gridstep /= 5;
-               im->ygrid_scale.labfact = 5;
-           }
-       }
-       else {
-           for(i=0;ylab[i].grid > 0;i++){
-               pixel = im->ysize / (scaledrange / ylab[i].grid);
-               if (gridind == -1 && pixel > 5) {
-                   gridind = i;
-                   break;
-               }
-           }
-           
-           for(i=0; i<4;i++) {
-              if (pixel * ylab[gridind].lfac[i] >=  2 * im->text_prop[TEXT_PROP_AXIS].size) {
-                 im->ygrid_scale.labfact =  ylab[gridind].lfac[i];
-                 break;
-              }                          
-           } 
-           
-           im->ygrid_scale.gridstep = ylab[gridind].grid * im->magfact;
-       }
+            if(range/im->ygrid_scale.gridstep > 5) {
+                im->ygrid_scale.labfact = 1;
+                if(range/im->ygrid_scale.gridstep > 8)
+                    im->ygrid_scale.labfact = 2;
+            }
+            else {
+                im->ygrid_scale.gridstep /= 5;
+                im->ygrid_scale.labfact = 5;
+            }
+            fractionals = floor(log10(im->ygrid_scale.gridstep*(double)im->ygrid_scale.labfact*im->viewfactor/im->magfact));
+            if(fractionals < 0) { /* small amplitude. */
+                int len = decimals - fractionals + 1;
+                if (im->unitslength < len+2) im->unitslength = len+2;
+                sprintf(im->ygrid_scale.labfmt, "%%%d.%df%s", len, -fractionals,(im->symbol != ' ' ? " %c" : ""));
+            } else {
+                int len = decimals + 1;
+                if (im->unitslength < len+2) im->unitslength = len+2;
+                sprintf(im->ygrid_scale.labfmt, "%%%d.0f%s", len, ( im->symbol != ' ' ? " %c" : "" ));
+            }
+        }
+        else {
+            for(i=0;ylab[i].grid > 0;i++){
+                pixel = im->ysize / (scaledrange / ylab[i].grid);
+                   gridind = i;
+                if (pixel > 7)
+                    break;
+            }
+            
+            for(i=0; i<4;i++) {
+               if (pixel * ylab[gridind].lfac[i] >=  2.5 * im->text_prop[TEXT_PROP_AXIS].size) {
+                  im->ygrid_scale.labfact =  ylab[gridind].lfac[i];
+                  break;
+               }
+            } 
+            
+            im->ygrid_scale.gridstep = ylab[gridind].grid * im->magfact;
+        }
     } else {
-       im->ygrid_scale.gridstep = im->ygridstep;
-       im->ygrid_scale.labfact = im->ylabfact;
+        im->ygrid_scale.gridstep = im->ygridstep;
+        im->ygrid_scale.labfact = im->ylabfact;
     }
     return 1;
 }
@@ -1590,140 +1661,328 @@ int draw_horizontal_grid(image_desc_t *im)
     int      i;
     double   scaledstep;
     char     graph_label[100];
+    int      nlabels=0;
     double X0=im->xorigin;
     double X1=im->xorigin+im->xsize;
    
     int sgrid = (int)( im->minval / im->ygrid_scale.gridstep - 1);
     int egrid = (int)( im->maxval / im->ygrid_scale.gridstep + 1);
-    scaledstep = im->ygrid_scale.gridstep/im->magfact;
+    double MaxY;
+    scaledstep = im->ygrid_scale.gridstep/(double)im->magfact*(double)im->viewfactor;
+    MaxY = scaledstep*(double)egrid;
     for (i = sgrid; i <= egrid; i++){
        double Y0=ytr(im,im->ygrid_scale.gridstep*i);
-       if ( Y0 >= im->yorigin-im->ysize
-                && Y0 <= im->yorigin){       
-           if(i % im->ygrid_scale.labfact == 0){               
-               if (i==0 || im->symbol == ' ') {
-                   if(scaledstep < 1){
-                       if(im->extra_flags & ALTYGRID) {
-                           sprintf(graph_label,im->ygrid_scale.labfmt,scaledstep*i);
-                       }
-                       else {
-                           sprintf(graph_label,"%4.1f",scaledstep*i);
-                       }
-                   } else {
-                       sprintf(graph_label,"%4.0f",scaledstep*i);
-                   }
-               }else {
-                   if(scaledstep < 1){
-                       sprintf(graph_label,"%4.1f %c",scaledstep*i, im->symbol);
-                   } else {
-                       sprintf(graph_label,"%4.0f %c",scaledstep*i, im->symbol);
-                   }
-               }
-
-              gfx_new_text ( im->canvas,
-                             X0-im->text_prop[TEXT_PROP_AXIS].size/1.5, Y0,
-                             im->graph_col[GRC_FONT],
-                             im->text_prop[TEXT_PROP_AXIS].font,
-                             im->text_prop[TEXT_PROP_AXIS].size,
-                             im->tabwidth, 0.0, GFX_H_RIGHT, GFX_V_CENTER,
-                             graph_label );
-              gfx_new_dashed_line ( im->canvas,
-                             X0-2,Y0,
-                             X1+2,Y0,
-                             MGRIDWIDTH, im->graph_col[GRC_MGRID],
-                             im->grid_dash_on, im->grid_dash_off);            
-              
-           } else if (!(im->extra_flags & NOMINOR)) {          
-              gfx_new_dashed_line ( im->canvas,
-                             X0-1,Y0,
-                             X1+1,Y0,
-                             GRIDWIDTH, im->graph_col[GRC_GRID],
-                             im->grid_dash_on, im->grid_dash_off);            
-              
-           }       
-       }       
+       double YN=ytr(im,im->ygrid_scale.gridstep*(i+1));
+       if ( floor(Y0+0.5) >= im->yorigin-im->ysize 
+            && floor(Y0+0.5) <= im->yorigin){       
+            /* Make sure at least 2 grid labels are shown, even if it doesn't agree
+               with the chosen settings. Add a label if required by settings, or if
+               there is only one label so far and the next grid line is out of bounds. */
+            if(i % im->ygrid_scale.labfact == 0 || ( nlabels==1 && (YN < im->yorigin-im->ysize || YN > im->yorigin) )){                
+                if (im->symbol == ' ') {
+                     if(im->extra_flags & ALTYGRID) {
+                        sprintf(graph_label,im->ygrid_scale.labfmt,scaledstep*(double)i);
+                    } else {
+                        if(MaxY < 10) {
+                           sprintf(graph_label,"%4.1f",scaledstep*(double)i);
+                          } else {
+                           sprintf(graph_label,"%4.0f",scaledstep*(double)i);
+                        }
+                    }
+                }else {
+                    char sisym = ( i == 0  ? ' ' : im->symbol);
+                     if(im->extra_flags & ALTYGRID) {
+                        sprintf(graph_label,im->ygrid_scale.labfmt,scaledstep*(double)i,sisym);
+                    } else {
+                          if(MaxY < 10){
+                             sprintf(graph_label,"%4.1f %c",scaledstep*(double)i, sisym);
+                        } else {
+                             sprintf(graph_label,"%4.0f %c",scaledstep*(double)i, sisym);
+                        }
+                    }
+                }
+                nlabels++;
+
+               gfx_new_text ( im->canvas,
+                              X0-im->text_prop[TEXT_PROP_AXIS].size, Y0,
+                              im->graph_col[GRC_FONT],
+                              im->text_prop[TEXT_PROP_AXIS].font,
+                              im->text_prop[TEXT_PROP_AXIS].size,
+                              im->tabwidth, 0.0, GFX_H_RIGHT, GFX_V_CENTER,
+                              graph_label );
+               gfx_new_dashed_line ( im->canvas,
+                              X0-2,Y0,
+                              X1+2,Y0,
+                              MGRIDWIDTH, im->graph_col[GRC_MGRID],
+                              im->grid_dash_on, im->grid_dash_off);               
+               
+            } else if (!(im->extra_flags & NOMINOR)) {                
+               gfx_new_dashed_line ( im->canvas,
+                              X0-1,Y0,
+                              X1+1,Y0,
+                              GRIDWIDTH, im->graph_col[GRC_GRID],
+                              im->grid_dash_on, im->grid_dash_off);               
+               
+            }            
+        }        
     } 
     return 1;
 }
 
+/* this is frexp for base 10 */
+double frexp10(double, double *);
+double frexp10(double x, double *e) {
+    double mnt;
+    int iexp;
+
+    iexp = floor(log(fabs(x)) / log(10));
+    mnt = x / pow(10.0, iexp);
+    if(mnt >= 10.0) {
+        iexp++;
+        mnt = x / pow(10.0, iexp);
+    }
+    *e = iexp;
+    return mnt;
+}
+
+static int AlmostEqual2sComplement (float A, float B, int maxUlps)
+{
+
+    int aInt = *(int*)&A;
+    int bInt = *(int*)&B;
+    int intDiff;
+    /* Make sure maxUlps is non-negative and small enough that the
+       default NAN won't compare as equal to anything.  */
+
+    /* assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); */
+
+    /* Make aInt lexicographically ordered as a twos-complement int */
+
+    if (aInt < 0)
+        aInt = 0x80000000l - aInt;
+
+    /* Make bInt lexicographically ordered as a twos-complement int */
+
+    if (bInt < 0)
+        bInt = 0x80000000l - bInt;
+
+    intDiff = abs(aInt - bInt);
+
+    if (intDiff <= maxUlps)
+        return 1;
+
+    return 0;
+}
+
 /* logaritmic horizontal grid */
 int
 horizontal_log_grid(image_desc_t   *im)   
 {
-    double   pixpex;
-    int      ii,i;
-    int      minoridx=0, majoridx=0;
-    char     graph_label[100];
-    double   X0,X1,Y0;   
-    double   value, pixperstep, minstep;
+    double yloglab[][10] = {
+        {1.0, 10., 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
+        {1.0, 5.0, 10., 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
+        {1.0, 2.0, 5.0, 7.0, 10., 0.0, 0.0, 0.0, 0.0, 0.0},
+        {1.0, 2.0, 4.0, 6.0, 8.0, 10., 0.0, 0.0, 0.0, 0.0},
+        {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.},
+        {0,0,0,0,0, 0,0,0,0,0} /* last line */ };
+
+    int i, j, val_exp, min_exp;
+    double nex;                /* number of decades in data */
+    double logscale;        /* scale in logarithmic space */
+    int exfrac = 1;        /* decade spacing */
+    int mid = -1;        /* row in yloglab for major grid */
+    double mspac;        /* smallest major grid spacing (pixels) */
+    int flab;                /* first value in yloglab to use */
+    double value, tmp, pre_value;
+    double X0,X1,Y0;   
+    char graph_label[100];
 
-    /* find grid spaceing */
-    pixpex= (double)im->ysize / (log10(im->maxval) - log10(im->minval));
+    nex = log10(im->maxval / im->minval);
+    logscale = im->ysize / nex;
 
-       if (isnan(pixpex)) {
-               return 0;
-       }
+    /* major spacing for data with high dynamic range */
+    while(logscale * exfrac < 3 * im->text_prop[TEXT_PROP_LEGEND].size) {
+        if(exfrac == 1) exfrac = 3;
+        else exfrac += 3;
+    }
 
-    for(i=0;yloglab[i][0] > 0;i++){
-       minstep = log10(yloglab[i][0]);
-       for(ii=1;yloglab[i][ii+1] > 0;ii++){
-           if(yloglab[i][ii+2]==0){
-               minstep = log10(yloglab[i][ii+1])-log10(yloglab[i][ii]);
-               break;
-           }
-       }
-       pixperstep = pixpex * minstep;
-       if(pixperstep > 5){minoridx = i;}
-       if(pixperstep > 2 *  im->text_prop[TEXT_PROP_LEGEND].size){majoridx = i;}
+    /* major spacing for less dynamic data */
+    do {
+        /* search best row in yloglab */
+        mid++;
+        for(i = 0; yloglab[mid][i + 1] < 10.0; i++);
+        mspac = logscale * log10(10.0 / yloglab[mid][i]);
+    } while(mspac > 2 * im->text_prop[TEXT_PROP_LEGEND].size && yloglab[mid][0] > 0);
+    if(mid) mid--;
+
+    /* find first value in yloglab */
+    for(flab = 0; yloglab[mid][flab] < 10 && frexp10(im->minval, &tmp) > yloglab[mid][flab] ; flab++);
+    if(yloglab[mid][flab] == 10.0) {
+        tmp += 1.0;
+        flab = 0;
+    }
+    val_exp = tmp;
+    if(val_exp % exfrac) val_exp += abs(-val_exp % exfrac);
+
+    X0=im->xorigin;
+    X1=im->xorigin+im->xsize;
+
+    /* draw grid */
+    pre_value = DNAN;
+    while(1) {       
+
+        value = yloglab[mid][flab] * pow(10.0, val_exp);
+        if (  AlmostEqual2sComplement(value,pre_value,4) ) break; /* it seems we are not converging */
+
+        pre_value = value;
+
+        Y0 = ytr(im, value);
+        if(floor(Y0+0.5) <= im->yorigin - im->ysize) break;
+
+        /* major grid line */
+        gfx_new_dashed_line ( im->canvas,
+            X0-2,Y0,
+            X1+2,Y0,
+            MGRIDWIDTH, im->graph_col[GRC_MGRID],
+            im->grid_dash_on, im->grid_dash_off);
+
+        /* label */
+        if (im->extra_flags & FORCE_UNITS_SI) {
+            int scale;
+            double pvalue;
+            char symbol;
+
+            scale = floor(val_exp / 3.0);
+            if( value >= 1.0 ) pvalue = pow(10.0, val_exp % 3);
+            else pvalue = pow(10.0, ((val_exp + 1) % 3) + 2);
+            pvalue *= yloglab[mid][flab];
+
+            if ( ((scale+si_symbcenter) < (int)sizeof(si_symbol)) &&
+                ((scale+si_symbcenter) >= 0) )
+                symbol = si_symbol[scale+si_symbcenter];
+            else
+                symbol = '?';
+
+                sprintf(graph_label,"%3.0f %c", pvalue, symbol);
+        } else
+            sprintf(graph_label,"%3.0e", value);
+        gfx_new_text ( im->canvas,
+            X0-im->text_prop[TEXT_PROP_AXIS].size, Y0,
+            im->graph_col[GRC_FONT],
+            im->text_prop[TEXT_PROP_AXIS].font,
+            im->text_prop[TEXT_PROP_AXIS].size,
+            im->tabwidth,0.0, GFX_H_RIGHT, GFX_V_CENTER,
+            graph_label );
+
+        /* minor grid */
+        if(mid < 4 && exfrac == 1) {
+            /* find first and last minor line behind current major line
+             * i is the first line and j tha last */
+            if(flab == 0) {
+                min_exp = val_exp - 1;
+                for(i = 1; yloglab[mid][i] < 10.0; i++);
+                i = yloglab[mid][i - 1] + 1;
+                j = 10;
+            }
+            else {
+                min_exp = val_exp;
+                i = yloglab[mid][flab - 1] + 1;
+                j = yloglab[mid][flab];
+            }
+
+            /* draw minor lines below current major line */
+            for(; i < j; i++) {
+
+                value = i * pow(10.0, min_exp);
+                if(value < im->minval) continue;
+
+                Y0 = ytr(im, value);
+                if(floor(Y0+0.5) <= im->yorigin - im->ysize) break;
+
+                /* draw lines */
+                gfx_new_dashed_line ( im->canvas,
+                    X0-1,Y0,
+                    X1+1,Y0,
+                    GRIDWIDTH, im->graph_col[GRC_GRID],
+                    im->grid_dash_on, im->grid_dash_off);
+            }
+        }
+        else if(exfrac > 1) {
+            for(i = val_exp - exfrac / 3 * 2; i < val_exp; i += exfrac / 3) {
+                value = pow(10.0, i);
+                if(value < im->minval) continue;
+
+                Y0 = ytr(im, value);
+                if(floor(Y0+0.5) <= im->yorigin - im->ysize) break;
+
+                /* draw lines */
+                gfx_new_dashed_line ( im->canvas,
+                    X0-1,Y0,
+                    X1+1,Y0,
+                    GRIDWIDTH, im->graph_col[GRC_GRID],
+                    im->grid_dash_on, im->grid_dash_off);
+            }
+        }
+
+        /* next decade */
+        if(yloglab[mid][++flab] == 10.0) {
+            flab = 0;
+            val_exp += exfrac;
+        }
     }
-   
-   X0=im->xorigin;
-   X1=im->xorigin+im->xsize;
-    /* paint minor grid */
-    for (value = pow((double)10, log10(im->minval) 
-                         - fmod(log10(im->minval),log10(yloglab[minoridx][0])));
-        value  <= im->maxval;
-        value *= yloglab[minoridx][0]){
-       if (value < im->minval) continue;
-       i=0;    
-       while(yloglab[minoridx][++i] > 0){          
-          Y0 = ytr(im,value * yloglab[minoridx][i]);
-          if (Y0 <= im->yorigin - im->ysize) break;
-          gfx_new_dashed_line ( im->canvas,
-                         X0-1,Y0,
-                         X1+1,Y0,
-                         GRIDWIDTH, im->graph_col[GRC_GRID],
-                         im->grid_dash_on, im->grid_dash_off);
-       }
+
+    /* draw minor lines after highest major line */
+    if(mid < 4 && exfrac == 1) {
+        /* find first and last minor line below current major line
+         * i is the first line and j tha last */
+        if(flab == 0) {
+            min_exp = val_exp - 1;
+            for(i = 1; yloglab[mid][i] < 10.0; i++);
+            i = yloglab[mid][i - 1] + 1;
+            j = 10;
+        }
+        else {
+            min_exp = val_exp;
+            i = yloglab[mid][flab - 1] + 1;
+            j = yloglab[mid][flab];
+        }
+
+        /* draw minor lines below current major line */
+        for(; i < j; i++) {
+
+            value = i * pow(10.0, min_exp);
+            if(value < im->minval) continue;
+
+            Y0 = ytr(im, value);
+            if(floor(Y0+0.5) <= im->yorigin - im->ysize) break;
+
+            /* draw lines */
+            gfx_new_dashed_line ( im->canvas,
+                X0-1,Y0,
+                X1+1,Y0,
+                GRIDWIDTH, im->graph_col[GRC_GRID],
+                im->grid_dash_on, im->grid_dash_off);
+        }
+    }
+    /* fancy minor gridlines */
+    else if(exfrac > 1) {
+        for(i = val_exp - exfrac / 3 * 2; i < val_exp; i += exfrac / 3) {
+            value = pow(10.0, i);
+            if(value < im->minval) continue;
+
+            Y0 = ytr(im, value);
+            if(floor(Y0+0.5) <= im->yorigin - im->ysize) break;
+
+            /* draw lines */
+            gfx_new_dashed_line ( im->canvas,
+                X0-1,Y0,
+                X1+1,Y0,
+                GRIDWIDTH, im->graph_col[GRC_GRID],
+                im->grid_dash_on, im->grid_dash_off);
+        }
     }
 
-    /* paint major grid and labels*/
-    for (value = pow((double)10, log10(im->minval) 
-                         - fmod(log10(im->minval),log10(yloglab[majoridx][0])));
-        value <= im->maxval;
-        value *= yloglab[majoridx][0]){
-       if (value < im->minval) continue;
-       i=0;    
-       while(yloglab[majoridx][++i] > 0){          
-          Y0 = ytr(im,value * yloglab[majoridx][i]);    
-          if (Y0 <= im->yorigin - im->ysize) break;
-          gfx_new_dashed_line ( im->canvas,
-                         X0-2,Y0,
-                         X1+2,Y0,
-                         MGRIDWIDTH, im->graph_col[GRC_MGRID],
-                         im->grid_dash_on, im->grid_dash_off);
-          
-          sprintf(graph_label,"%3.0e",value * yloglab[majoridx][i]);
-          gfx_new_text ( im->canvas,
-                         X0-im->text_prop[TEXT_PROP_AXIS].size/1.5, Y0,
-                         im->graph_col[GRC_FONT],
-                         im->text_prop[TEXT_PROP_AXIS].font,
-                         im->text_prop[TEXT_PROP_AXIS].size,
-                         im->tabwidth,0.0, GFX_H_RIGHT, GFX_V_CENTER,
-                         graph_label );
-       } 
-    }
-       return 1;
+    return 1;
 }
 
 
@@ -1731,7 +1990,7 @@ void
 vertical_grid(
     image_desc_t   *im )
 {   
-    int xlab_sel;              /* which sort of label and grid ? */
+    int xlab_sel;                /* which sort of label and grid ? */
     time_t ti, tilab, timajor;
     long factor;
     char graph_label[100];
@@ -1743,18 +2002,20 @@ vertical_grid(
     
     
     if(im->xlab_user.minsec == -1){
-       factor=(im->end - im->start)/im->xsize;
-       xlab_sel=0;
-       while ( xlab[xlab_sel+1].minsec != -1 
-               && xlab[xlab_sel+1].minsec <= factor){ xlab_sel++; }
-       im->xlab_user.gridtm = xlab[xlab_sel].gridtm;
-       im->xlab_user.gridst = xlab[xlab_sel].gridst;
-       im->xlab_user.mgridtm = xlab[xlab_sel].mgridtm;
-       im->xlab_user.mgridst = xlab[xlab_sel].mgridst;
-       im->xlab_user.labtm = xlab[xlab_sel].labtm;
-       im->xlab_user.labst = xlab[xlab_sel].labst;
-       im->xlab_user.precis = xlab[xlab_sel].precis;
-       im->xlab_user.stst = xlab[xlab_sel].stst;
+        factor=(im->end - im->start)/im->xsize;
+        xlab_sel=0;
+        while ( xlab[xlab_sel+1].minsec != -1 
+                && xlab[xlab_sel+1].minsec <= factor) { xlab_sel++; }        /* pick the last one */
+        while ( xlab[xlab_sel-1].minsec == xlab[xlab_sel].minsec
+                && xlab[xlab_sel].length > (im->end - im->start)) { xlab_sel--; }        /* go back to the smallest size */
+        im->xlab_user.gridtm = xlab[xlab_sel].gridtm;
+        im->xlab_user.gridst = xlab[xlab_sel].gridst;
+        im->xlab_user.mgridtm = xlab[xlab_sel].mgridtm;
+        im->xlab_user.mgridst = xlab[xlab_sel].mgridst;
+        im->xlab_user.labtm = xlab[xlab_sel].labtm;
+        im->xlab_user.labst = xlab[xlab_sel].labst;
+        im->xlab_user.precis = xlab[xlab_sel].precis;
+        im->xlab_user.stst = xlab[xlab_sel].stst;
     }
     
     /* y coords are the same for every line ... */
@@ -1791,43 +2052,43 @@ vertical_grid(
 
     /* paint the major grid */
     for(ti = find_first_time(im->start,
-                           im->xlab_user.mgridtm,
-                           im->xlab_user.mgridst);
-       ti < im->end; 
-       ti = find_next_time(ti,im->xlab_user.mgridtm,im->xlab_user.mgridst)
-       ){
-       /* are we inside the graph ? */
-       if (ti < im->start || ti > im->end) continue;
+                            im->xlab_user.mgridtm,
+                            im->xlab_user.mgridst);
+        ti < im->end; 
+        ti = find_next_time(ti,im->xlab_user.mgridtm,im->xlab_user.mgridst)
+        ){
+        /* are we inside the graph ? */
+        if (ti < im->start || ti > im->end) continue;
        X0 = xtr(im,ti);
        gfx_new_dashed_line(im->canvas,X0,Y0+3, X0,Y1-2,MGRIDWIDTH,
-          im->graph_col[GRC_MGRID],
-          im->grid_dash_on, im->grid_dash_off);
+           im->graph_col[GRC_MGRID],
+           im->grid_dash_on, im->grid_dash_off);
        
     }
     /* paint the labels below the graph */
-    for(ti = find_first_time(im->start,
-                           im->xlab_user.labtm,
-                           im->xlab_user.labst);
-       ti <= im->end
-       ti = find_next_time(ti,im->xlab_user.labtm,im->xlab_user.labst)
-       ){
+    for(ti = find_first_time(im->start - im->xlab_user.precis/2,
+                            im->xlab_user.labtm,
+                            im->xlab_user.labst);
+        ti <= im->end - im->xlab_user.precis/2
+        ti = find_next_time(ti,im->xlab_user.labtm,im->xlab_user.labst)
+        ){
         tilab= ti + im->xlab_user.precis/2; /* correct time for the label */
-       /* are we inside the graph ? */
-       if (ti < im->start || ti > im->end) continue;
+        /* are we inside the graph ? */
+        if (tilab < im->start || tilab > im->end) continue;
 
 #if HAVE_STRFTIME
-       localtime_r(&tilab, &tm);
-       strftime(graph_label,99,im->xlab_user.stst, &tm);
+        localtime_r(&tilab, &tm);
+        strftime(graph_label,99,im->xlab_user.stst, &tm);
 #else
 # error "your libc has no strftime I guess we'll abort the exercise here."
 #endif
        gfx_new_text ( im->canvas,
-                     xtr(im,tilab), Y0+im->text_prop[TEXT_PROP_AXIS].size/1.5,
-                     im->graph_col[GRC_FONT],
-                     im->text_prop[TEXT_PROP_AXIS].font,
-                     im->text_prop[TEXT_PROP_AXIS].size,
-                     im->tabwidth, 0.0, GFX_H_CENTER, GFX_V_TOP,
-                     graph_label );
+                      xtr(im,tilab), Y0+im->text_prop[TEXT_PROP_AXIS].size*1.4+5,
+                      im->graph_col[GRC_FONT],
+                      im->text_prop[TEXT_PROP_AXIS].font,
+                      im->text_prop[TEXT_PROP_AXIS].size,
+                      im->tabwidth, 0.0, GFX_H_CENTER, GFX_V_BOTTOM,
+                      graph_label );
        
     }
 
@@ -1837,32 +2098,38 @@ vertical_grid(
 void 
 axis_paint(
    image_desc_t   *im
-          )
+           )
 {   
     /* draw x and y axis */
     /* gfx_new_line ( im->canvas, im->xorigin+im->xsize,im->yorigin,
-                     im->xorigin+im->xsize,im->yorigin-im->ysize,
-                     GRIDWIDTH, im->graph_col[GRC_AXIS]);
+                      im->xorigin+im->xsize,im->yorigin-im->ysize,
+                      GRIDWIDTH, im->graph_col[GRC_AXIS]);
        
        gfx_new_line ( im->canvas, im->xorigin,im->yorigin-im->ysize,
-                        im->xorigin+im->xsize,im->yorigin-im->ysize,
-                        GRIDWIDTH, im->graph_col[GRC_AXIS]); */
+                         im->xorigin+im->xsize,im->yorigin-im->ysize,
+                         GRIDWIDTH, im->graph_col[GRC_AXIS]); */
    
        gfx_new_line ( im->canvas, im->xorigin-4,im->yorigin,
-                        im->xorigin+im->xsize+4,im->yorigin,
-                        MGRIDWIDTH, im->graph_col[GRC_AXIS]);
+                         im->xorigin+im->xsize+4,im->yorigin,
+                         MGRIDWIDTH, im->graph_col[GRC_AXIS]);
    
        gfx_new_line ( im->canvas, im->xorigin,im->yorigin+4,
-                        im->xorigin,im->yorigin-im->ysize-4,
-                        MGRIDWIDTH, im->graph_col[GRC_AXIS]);
+                         im->xorigin,im->yorigin-im->ysize-4,
+                         MGRIDWIDTH, im->graph_col[GRC_AXIS]);
    
     
-    /* arrow for X axis direction */
+    /* arrow for X and Y axis direction */
+    gfx_new_area ( im->canvas, 
+                   im->xorigin+im->xsize+2,  im->yorigin-2,
+                   im->xorigin+im->xsize+2,  im->yorigin+3,
+                   im->xorigin+im->xsize+7,  im->yorigin+0.5, /* LINEOFFSET */
+                   im->graph_col[GRC_ARROW]);
+
     gfx_new_area ( im->canvas, 
-                  im->xorigin+im->xsize+3,  im->yorigin-3,
-                  im->xorigin+im->xsize+3,  im->yorigin+4,
-                  im->xorigin+im->xsize+8,  im->yorigin+0.5, /* LINEOFFSET */
-                  im->graph_col[GRC_ARROW]);
+                   im->xorigin-2,  im->yorigin-im->ysize-2,
+                   im->xorigin+3,  im->yorigin-im->ysize-2,
+                   im->xorigin+0.5,    im->yorigin-im->ysize-7, /* LINEOFFSET */
+                   im->graph_col[GRC_ARROW]);
 
 }
 
@@ -1897,27 +2164,27 @@ grid_paint(image_desc_t   *im)
       vertical_grid(im);
     
     if (im->draw_y_grid == 1){
-       if(im->logarithmic){
-               res = horizontal_log_grid(im);
-       } else {
-               res = draw_horizontal_grid(im);
-       }
-
-       /* dont draw horizontal grid if there is no min and max val */
-       if (! res ) {
-         char *nodata = "No Data found";
-          gfx_new_text(im->canvas,im->ximg/2, (2*im->yorigin-im->ysize) / 2,
-                       im->graph_col[GRC_FONT],
-                       im->text_prop[TEXT_PROP_AXIS].font,
-                       im->text_prop[TEXT_PROP_AXIS].size,
-                       im->tabwidth, 0.0, GFX_H_CENTER, GFX_V_CENTER,
-                       nodata );          
-       }
+        if(im->logarithmic){
+                res = horizontal_log_grid(im);
+        } else {
+                res = draw_horizontal_grid(im);
+        }
+        
+        /* dont draw horizontal grid if there is no min and max val */
+        if (! res ) {
+          char *nodata = "No Data found";
+           gfx_new_text(im->canvas,im->ximg/2, (2*im->yorigin-im->ysize) / 2,
+                        im->graph_col[GRC_FONT],
+                        im->text_prop[TEXT_PROP_AXIS].font,
+                        im->text_prop[TEXT_PROP_AXIS].size,
+                        im->tabwidth, 0.0, GFX_H_CENTER, GFX_V_CENTER,
+                        nodata );           
+        }
     }
 
     /* yaxis unit description */
     gfx_new_text( im->canvas,
-                  7, (im->yorigin - im->ysize/2),
+                  10, (im->yorigin - im->ysize/2),
                   im->graph_col[GRC_FONT],
                   im->text_prop[TEXT_PROP_UNIT].font,
                   im->text_prop[TEXT_PROP_UNIT].size, im->tabwidth, 
@@ -1927,12 +2194,31 @@ grid_paint(image_desc_t   *im)
 
     /* graph title */
     gfx_new_text( im->canvas,
-                 im->ximg/2, im->text_prop[TEXT_PROP_TITLE].size*1.2,
-                 im->graph_col[GRC_FONT],
-                 im->text_prop[TEXT_PROP_TITLE].font,
-                 im->text_prop[TEXT_PROP_TITLE].size, im->tabwidth, 0.0,
-                 GFX_H_CENTER, GFX_V_CENTER,
-                 im->title);
+                  im->ximg/2, im->text_prop[TEXT_PROP_TITLE].size*1.3+4,
+                  im->graph_col[GRC_FONT],
+                  im->text_prop[TEXT_PROP_TITLE].font,
+                  im->text_prop[TEXT_PROP_TITLE].size, im->tabwidth, 0.0,
+                  GFX_H_CENTER, GFX_V_CENTER,
+                  im->title);
+    /* rrdtool 'logo' */
+    gfx_new_text( im->canvas,
+                  im->ximg-7, 7,
+                  ( im->graph_col[GRC_FONT] & 0xffffff00 ) | 0x00000044,
+                  im->text_prop[TEXT_PROP_AXIS].font,
+                  5.5, im->tabwidth, 270,
+                  GFX_H_RIGHT, GFX_V_TOP,
+                  "RRDTOOL / TOBI OETIKER");
+
+    /* graph watermark */
+    if(im->watermark[0] != '\0') {
+        gfx_new_text( im->canvas,
+                  im->ximg/2, im->yimg-6,
+                  ( im->graph_col[GRC_FONT] & 0xffffff00 ) | 0x00000044,
+                  im->text_prop[TEXT_PROP_AXIS].font,
+                  5.5, im->tabwidth, 0,
+                  GFX_H_CENTER, GFX_V_BOTTOM,
+                  im->watermark);
+    }
     
     /* graph labels */
     if( !(im->extra_flags & NOLEGEND) & !(im->extra_flags & ONLY_GRAPH) ) {
@@ -1944,24 +2230,32 @@ grid_paint(image_desc_t   *im)
                     X0 = im->gdes[i].leg_x;
                     Y0 = im->gdes[i].leg_y;
                     gfx_new_text ( im->canvas, X0, Y0,
-                                  im->graph_col[GRC_FONT],
-                                  im->text_prop[TEXT_PROP_LEGEND].font,
-                                  im->text_prop[TEXT_PROP_LEGEND].size,
-                                  im->tabwidth,0.0, GFX_H_LEFT, GFX_V_BOTTOM,
-                                  im->gdes[i].legend );
-                   /* The legend for GRAPH items starts with "M " to have
+                                   im->graph_col[GRC_FONT],
+                                   im->text_prop[TEXT_PROP_LEGEND].font,
+                                   im->text_prop[TEXT_PROP_LEGEND].size,
+                                   im->tabwidth,0.0, GFX_H_LEFT, GFX_V_BOTTOM,
+                                   im->gdes[i].legend );
+                    /* The legend for GRAPH items starts with "M " to have
                        enough space for the box */
-                    if (          im->gdes[i].gf != GF_PRINT &&
-                                  im->gdes[i].gf != GF_GPRINT &&
+                    if (           im->gdes[i].gf != GF_PRINT &&
+                                   im->gdes[i].gf != GF_GPRINT &&
                                    im->gdes[i].gf != GF_COMMENT) {
                             int boxH, boxV;
                             
                             boxH = gfx_get_text_width(im->canvas, 0,
                                                       im->text_prop[TEXT_PROP_LEGEND].font,
                                                       im->text_prop[TEXT_PROP_LEGEND].size,
-                                                      im->tabwidth,"M", 0)*1.2;
-                            boxV = boxH;
+                                                      im->tabwidth,"o", 0) * 1.2;
+                            boxV = boxH*1.1;
                             
+                            /* make sure transparent colors show up the same way as in the graph */
+                             node = gfx_new_area(im->canvas,
+                                                X0,Y0-boxV,
+                                                X0,Y0,
+                                                X0+boxH,Y0,
+                                                im->graph_col[GRC_BACK]);
+                            gfx_add_point ( node, X0+boxH, Y0-boxV );
+
                             node = gfx_new_area(im->canvas,
                                                 X0,Y0-boxV,
                                                 X0,Y0,
@@ -1969,8 +2263,9 @@ grid_paint(image_desc_t   *im)
                                                 im->gdes[i].col);
                             gfx_add_point ( node, X0+boxH, Y0-boxV );
                             node = gfx_new_line(im->canvas,
-                                                X0,Y0-boxV, X0,Y0,
-                                                1,0x000000FF);
+                                                X0,Y0-boxV,
+                                                X0,Y0,
+                                                1.0,im->graph_col[GRC_FRAME]);
                             gfx_add_point(node,X0+boxH,Y0);
                             gfx_add_point(node,X0+boxH,Y0-boxV);
                             gfx_close_path(node);
@@ -1986,7 +2281,7 @@ grid_paint(image_desc_t   *im)
 
 int lazy_check(image_desc_t *im){
     FILE *fd = NULL;
-       int size = 1;
+        int size = 1;
     struct stat  imgstat;
     
     if (im->lazy == 0) return 0; /* no lazy option */
@@ -1995,16 +2290,16 @@ int lazy_check(image_desc_t *im){
     /* one pixel in the existing graph is more then what we would
        change here ... */
     if (time(NULL) - imgstat.st_mtime > 
-       (im->end - im->start) / im->xsize) 
+        (im->end - im->start) / im->xsize) 
       return 0;
     if ((fd = fopen(im->graphfile,"rb")) == NULL) 
       return 0; /* the file does not exist */
     switch (im->canvas->imgformat) {
     case IF_PNG:
-          size = PngSize(fd,&(im->ximg),&(im->yimg));
-          break;
+           size = PngSize(fd,&(im->ximg),&(im->yimg));
+           break;
     default:
-          size = 1;
+           size = 1;
     }
     fclose(fd);
     return size;
@@ -2013,15 +2308,15 @@ int lazy_check(image_desc_t *im){
 #ifdef WITH_PIECHART
 void
 pie_part(image_desc_t *im, gfx_color_t color,
-           double PieCenterX, double PieCenterY, double Radius,
-           double startangle, double endangle)
+            double PieCenterX, double PieCenterY, double Radius,
+            double startangle, double endangle)
 {
     gfx_node_t *node;
     double angle;
     double step=M_PI/50; /* Number of iterations for the circle;
-                        ** 10 is definitely too low, more than
-                        ** 50 seems to be overkill
-                        */
+                         ** 10 is definitely too low, more than
+                         ** 50 seems to be overkill
+                         */
 
     /* Strange but true: we have to work clockwise or else
     ** anti aliasing nor transparency don't work.
@@ -2038,22 +2333,22 @@ pie_part(image_desc_t *im, gfx_color_t color,
     /* Hidden feature: Radius decreases each full circle */
     angle=startangle;
     while (angle>=2*M_PI) {
-       angle  -= 2*M_PI;
-       Radius *= 0.8;
+        angle  -= 2*M_PI;
+        Radius *= 0.8;
     }
 
     node=gfx_new_area(im->canvas,
-               PieCenterX+sin(startangle)*Radius,
-               PieCenterY-cos(startangle)*Radius,
-               PieCenterX,
-               PieCenterY,
-               PieCenterX+sin(endangle)*Radius,
-               PieCenterY-cos(endangle)*Radius,
-               color);
+                PieCenterX+sin(startangle)*Radius,
+                PieCenterY-cos(startangle)*Radius,
+                PieCenterX,
+                PieCenterY,
+                PieCenterX+sin(endangle)*Radius,
+                PieCenterY-cos(endangle)*Radius,
+                color);
     for (angle=endangle;angle-startangle>=step;angle-=step) {
-       gfx_add_point(node,
-               PieCenterX+sin(angle)*Radius,
-               PieCenterY-cos(angle)*Radius );
+        gfx_add_point(node,
+                PieCenterX+sin(angle)*Radius,
+                PieCenterY-cos(angle)*Radius );
     }
 }
 
@@ -2087,62 +2382,72 @@ graph_size_location(image_desc_t *im, int elements
     ** |v+--+-------------------------------+--------+
     ** | |..............legends......................|
     ** +-+-------------------------------------------+
+    ** |                 watermark                   |
+    ** +---------------------------------------------+
     */
-    int Xvertical=0,   Yvertical=0,
-       Xtitle   =0,    Ytitle   =0,
-       Xylabel  =0,    Yylabel  =0,
-       Xmain    =0,    Ymain    =0,
-       Xpie     =0,    Ypie     =0,
-       Xxlabel  =0,    Yxlabel  =0,
+    int Xvertical=0,        
+                        Ytitle   =0,
+        Xylabel  =0,        
+        Xmain    =0,        Ymain    =0,
+#ifdef WITH_PIECHART
+        Xpie     =0,        Ypie     =0,
+#endif
+                        Yxlabel  =0,
 #if 0
-       Xlegend  =0,    Ylegend  =0,
+        Xlegend  =0,        Ylegend  =0,
 #endif
-        Xspacing =10,  Yspacing =10;
+        Xspacing =15,  Yspacing =15,
+       
+                      Ywatermark =4;
 
     if (im->extra_flags & ONLY_GRAPH) {
-       Xspacing =0;
-       Yspacing =0;
-    } else {
-        if (im->ylegend[0] != '\0') {
+        im->xorigin =0;
+        im->ximg = im->xsize;
+        im->yimg = im->ysize;
+        im->yorigin = im->ysize;
+        ytr(im,DNAN); 
+        return 0;
+    }
+
+    if (im->ylegend[0] != '\0' ) {
            Xvertical = im->text_prop[TEXT_PROP_UNIT].size *2;
-           Yvertical = gfx_get_text_width(im->canvas, 0,
-                                          im->text_prop[TEXT_PROP_UNIT].font,
-                                          im->text_prop[TEXT_PROP_UNIT].size,
-                                          im->tabwidth,im->ylegend, 0);
-        }
     }
 
+
     if (im->title[0] != '\0') {
-       /* The title is placed "inbetween" two text lines so it
-       ** automatically has some vertical spacing.  The horizontal
-       ** spacing is added here, on each side.
-       */
-       Xtitle = gfx_get_text_width(im->canvas, 0,
-               im->text_prop[TEXT_PROP_TITLE].font,
-               im->text_prop[TEXT_PROP_TITLE].size,
-               im->tabwidth,
-               im->title, 0) + 2*Xspacing;
-       Ytitle = im->text_prop[TEXT_PROP_TITLE].size*2.5;
+        /* The title is placed "inbetween" two text lines so it
+        ** automatically has some vertical spacing.  The horizontal
+        ** spacing is added here, on each side.
+        */
+        /* don't care for the with of the title
+                Xtitle = gfx_get_text_width(im->canvas, 0,
+                im->text_prop[TEXT_PROP_TITLE].font,
+                im->text_prop[TEXT_PROP_TITLE].size,
+                im->tabwidth,
+                im->title, 0) + 2*Xspacing; */
+        Ytitle = im->text_prop[TEXT_PROP_TITLE].size*2.6+10;
     }
 
     if (elements) {
-       Xmain=im->xsize;
-       Ymain=im->ysize;
-       if (im->draw_x_grid) {
-           Xxlabel=Xmain;
-           Yxlabel=im->text_prop[TEXT_PROP_AXIS].size *2.5;
-       }
-       if (im->draw_y_grid) {
-           Xylabel=im->text_prop[TEXT_PROP_AXIS].size *6;
-           Yylabel=Ymain;
-       }
+        Xmain=im->xsize;
+        Ymain=im->ysize;
+        if (im->draw_x_grid) {
+            Yxlabel=im->text_prop[TEXT_PROP_AXIS].size *2.5;
+        }
+        if (im->draw_y_grid || im->forceleftspace ) {
+            Xylabel=gfx_get_text_width(im->canvas, 0,
+                        im->text_prop[TEXT_PROP_AXIS].font,
+                        im->text_prop[TEXT_PROP_AXIS].size,
+                        im->tabwidth,
+                        "0", 0) * im->unitslength;
+        }
     }
 
 #ifdef WITH_PIECHART
     if (piechart) {
-       im->piesize=im->xsize<im->ysize?im->xsize:im->ysize;
-       Xpie=im->piesize;
-       Ypie=im->piesize;
+        im->piesize=im->xsize<im->ysize?im->xsize:im->ysize;
+        Xpie=im->piesize;
+        Ypie=im->piesize;
     }
 #endif
 
@@ -2157,78 +2462,73 @@ graph_size_location(image_desc_t *im, int elements
     ** forget about it at all; the legend will have to fit in the
     ** size already allocated.
     */
-    im->ximg = Xmain;
+    im->ximg = Xylabel + Xmain + 2 * Xspacing;
 
-    if ( !(im->extra_flags & ONLY_GRAPH) ) {
-        im->ximg = Xylabel + Xmain + Xpie + 2 * Xspacing;
-    }
+#ifdef WITH_PIECHART
+    im->ximg  += Xpie;
+#endif
 
     if (Xmain) im->ximg += Xspacing;
+#ifdef WITH_PIECHART
     if (Xpie) im->ximg += Xspacing;
+#endif
 
-    if (im->extra_flags & ONLY_GRAPH) {
-       im->xorigin = 0;
-    } else {
-       im->xorigin = Xspacing + Xylabel;
-    }
+    im->xorigin = Xspacing + Xylabel;
+
+    /* the length of the title should not influence with width of the graph
+       if (Xtitle > im->ximg) im->ximg = Xtitle; */
 
-    if (Xtitle > im->ximg) im->ximg = Xtitle;
-    if (Xvertical) {
-       im->ximg += Xvertical;
-       im->xorigin += Xvertical;
+    if (Xvertical) { /* unit description */
+        im->ximg += Xvertical;
+        im->xorigin += Xvertical;
     }
     xtr(im,0);
 
     /* The vertical size is interesting... we need to compare
-    ** the sum of {Ytitle, Ymain, Yxlabel, Ylegend} with Yvertical
-    ** however we need to know {Ytitle+Ymain+Yxlabel} in order to
-    ** start even thinking about Ylegend.
+    ** the sum of {Ytitle, Ymain, Yxlabel, Ylegend, Ywatermark} with 
+    ** Yvertical however we need to know {Ytitle+Ymain+Yxlabel}
+    ** in order to start even thinking about Ylegend or Ywatermark.
     **
     ** Do it in three portions: First calculate the inner part,
-    ** then do the legend, then adjust the total height of the img.
+    ** then do the legend, then adjust the total height of the img,
+    ** adding space for a watermark if one exists;
     */
 
     /* reserve space for main and/or pie */
 
-    if (im->extra_flags & ONLY_GRAPH) {
-        im->yimg = Ymain;
-    } else {
-        im->yimg = Ymain + Yxlabel;
-    }
-
+    im->yimg = Ymain + Yxlabel;
+    
+#ifdef WITH_PIECHART
     if (im->yimg < Ypie) im->yimg = Ypie;
+#endif
 
-    if (im->extra_flags & ONLY_GRAPH) {
-        im->yorigin = im->yimg;
-    } else {
-        im->yorigin = im->yimg - Yxlabel;
-    }
+    im->yorigin = im->yimg - Yxlabel;
 
     /* reserve space for the title *or* some padding above the graph */
     if (Ytitle) {
-       im->yimg += Ytitle;
-       im->yorigin += Ytitle;
+        im->yimg += Ytitle;
+        im->yorigin += Ytitle;
     } else {
-       im->yimg += Yspacing;
-       im->yorigin += Yspacing;
+        im->yimg += 1.5*Yspacing;
+        im->yorigin += 1.5*Yspacing;
     }
     /* reserve space for padding below the graph */
     im->yimg += Yspacing;
-    ytr(im,DNAN);
-
+     
     /* Determine where to place the legends onto the image.
     ** Adjust im->yimg to match the space requirements.
     */
     if(leg_place(im)==-1)
-       return -1;
-
-    /* last of three steps: check total height of image */
-    if (im->yimg < Yvertical) im->yimg = Yvertical;
+        return -1;
+        
+    if (im->watermark[0] != '\0') {
+        im->yimg += Ywatermark;
+    }
 
 #if 0
     if (Xlegend > im->ximg) {
-       im->ximg = Xlegend;
-       /* reposition Pie */
+        im->ximg = Xlegend;
+        /* reposition Pie */
     }
 #endif
 
@@ -2238,17 +2538,23 @@ graph_size_location(image_desc_t *im, int elements
     ** padding.
     */
     if (elements) {
-       im->pie_x = im->ximg - Xspacing - Xpie/2;
+        im->pie_x = im->ximg - Xspacing - Xpie/2;
         im->pie_y = im->yorigin-Ymain+Ypie/2;
     } else {
-       im->pie_x = im->ximg/2;
+        im->pie_x = im->ximg/2;
         im->pie_y = im->yorigin-Ypie/2;
     }
 #endif
 
+    ytr(im,DNAN);
     return 0;
 }
 
+/* from http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm */
+/* yes we are loosing precision by doing tos with floats instead of doubles
+   but it seems more stable this way. */
+   
+
 /* draw that picture thing ... */
 int
 graph_paint(image_desc_t *im, char ***calcpr)
@@ -2263,7 +2569,6 @@ graph_paint(image_desc_t *im, char ***calcpr)
   gfx_node_t *node;
   
   double areazero = 0.0;
-  enum gf_en stack_gf = GF_PRINT;
   graph_desc_t *lastgdes = NULL;    
 
   /* if we are lazy and there is nothing to PRINT ... quit now */
@@ -2339,11 +2644,11 @@ graph_paint(image_desc_t *im, char ***calcpr)
   
   node=gfx_new_area ( im->canvas,
                       0, 0,
-                      im->ximg, 0,
-                      im->ximg, im->yimg,
+                      0, im->yimg,
+                      im->ximg, im->yimg,                      
                       im->graph_col[GRC_BACK]);
 
-  gfx_add_point(node,0, im->yimg);
+  gfx_add_point(node,im->ximg, 0);
 
 #ifdef WITH_PIECHART
   if (piechart != 2) {
@@ -2387,22 +2692,27 @@ graph_paint(image_desc_t *im, char ***calcpr)
       for (ii = 0; ii < im->xsize; ii++)
         {
           if (!isnan(im->gdes[i].p_data[ii]) && 
-              im->gdes[i].p_data[ii] > 0.0)
-            { 
-              /* generate a tick */
-              gfx_new_line(im->canvas, im -> xorigin + ii, 
-                           im -> yorigin - (im -> gdes[i].yrule * im -> ysize),
-                           im -> xorigin + ii, 
-                           im -> yorigin,
-                           1.0,
-                           im -> gdes[i].col );
-            }
+              im->gdes[i].p_data[ii] != 0.0)
+           { 
+              if (im -> gdes[i].yrule > 0 ) {
+                      gfx_new_line(im->canvas,
+                                   im -> xorigin + ii, im->yorigin,
+                                   im -> xorigin + ii, im->yorigin - im -> gdes[i].yrule * im -> ysize,
+                                   1.0,
+                                   im -> gdes[i].col );
+              } else if ( im -> gdes[i].yrule < 0 ) {
+                      gfx_new_line(im->canvas,
+                                   im -> xorigin + ii, im->yorigin - im -> ysize,
+                                   im -> xorigin + ii, im->yorigin - ( 1 - im -> gdes[i].yrule ) * im -> ysize,
+                                   1.0,
+                                   im -> gdes[i].col );
+              
+              }
+           }
         }
       break;
     case GF_LINE:
     case GF_AREA:
-      stack_gf = im->gdes[i].gf;
-    case GF_STACK:          
       /* fix data points at oo and -oo */
       for(ii=0;ii<im->xsize;ii++){
         if (isinf(im->gdes[i].p_data[ii])){
@@ -2414,84 +2724,145 @@ graph_paint(image_desc_t *im, char ***calcpr)
           
         }
       } /* for */
-      
-      if (im->gdes[i].col != 0x0){               
+
+      /* *******************************************************
+       a           ___. (a,t) 
+                    |   |    ___
+              ____|   |   |   |
+              |       |___|
+       -------|--t-1--t--------------------------------      
+                      
+      if we know the value at time t was a then 
+      we draw a square from t-1 to t with the value a.
+
+      ********************************************************* */
+      if (im->gdes[i].col != 0x0){   
         /* GF_LINE and friend */
-        if(stack_gf == GF_LINE ){
+        if(im->gdes[i].gf == GF_LINE ){
+          double last_y=0.0;
           node = NULL;
           for(ii=1;ii<im->xsize;ii++){
-            if ( ! isnan(im->gdes[i].p_data[ii-1])
-                 && ! isnan(im->gdes[i].p_data[ii])){
-              if (node == NULL){
-                node = gfx_new_line(im->canvas,
+            if (isnan(im->gdes[i].p_data[ii]) || (im->slopemode==1 && isnan(im->gdes[i].p_data[ii-1]))){
+                node = NULL;
+                continue;
+            }
+            if ( node == NULL ) {
+                     last_y = ytr(im,im->gdes[i].p_data[ii]);
+                if ( im->slopemode == 0 ){
+                  node = gfx_new_line(im->canvas,
+                                    ii-1+im->xorigin,last_y,
+                                    ii+im->xorigin,last_y,
+                                    im->gdes[i].linewidth,
+                                    im->gdes[i].col);
+                } else {
+                  node = gfx_new_line(im->canvas,
                                     ii-1+im->xorigin,ytr(im,im->gdes[i].p_data[ii-1]),
-                                    ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]),
+                                    ii+im->xorigin,last_y,
                                     im->gdes[i].linewidth,
                                     im->gdes[i].col);
-              } else {
-                gfx_add_point(node,ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]));
-              }
-            } else {
-              node = NULL;
-            }
+                }
+             } else {
+               double new_y = ytr(im,im->gdes[i].p_data[ii]);
+               if ( im->slopemode==0 && ! AlmostEqual2sComplement(new_y,last_y,4)){
+                   gfx_add_point(node,ii-1+im->xorigin,new_y);
+               };
+               last_y = new_y;
+               gfx_add_point(node,ii+im->xorigin,new_y);
+             };
+
           }
         } else {
-          int area_start=-1;
-          node = NULL;
-          for(ii=1;ii<im->xsize;ii++){
-            /* open an area */
-            if ( ! isnan(im->gdes[i].p_data[ii-1])
-                 && ! isnan(im->gdes[i].p_data[ii])){
-              if (node == NULL){
-                float ybase = 0.0;
-/*
-                if (im->gdes[i].gf == GF_STACK) {
-*/
-               if ( (im->gdes[i].gf == GF_STACK)
-                 || (im->gdes[i].stack) ) {
-
-                  ybase = ytr(im,lastgdes->p_data[ii-1]);
-                } else {
-                  ybase =  ytr(im,areazero);
-                }
-                area_start = ii-1;
-                node = gfx_new_area(im->canvas,
-                                    ii-1+im->xorigin,ybase,
-                                    ii-1+im->xorigin,ytr(im,im->gdes[i].p_data[ii-1]),
-                                    ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]),
-                                    im->gdes[i].col
-                                    );
-              } else {
-                gfx_add_point(node,ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]));
-              }
+          int idxI=-1;
+          double *foreY=malloc(sizeof(double)*im->xsize*2);
+          double *foreX=malloc(sizeof(double)*im->xsize*2);
+          double *backY=malloc(sizeof(double)*im->xsize*2);
+          double *backX=malloc(sizeof(double)*im->xsize*2);
+          int drawem = 0;
+          for(ii=0;ii<=im->xsize;ii++){
+            double ybase,ytop;
+            if ( idxI > 0 && ( drawem != 0 || ii==im->xsize)){
+               int cntI=1;
+               int lastI=0;
+               while (cntI < idxI && AlmostEqual2sComplement(foreY[lastI],foreY[cntI],4) && AlmostEqual2sComplement(foreY[lastI],foreY[cntI+1],4)){cntI++;}
+               node = gfx_new_area(im->canvas,
+                                backX[0],backY[0],
+                                foreX[0],foreY[0],
+                                foreX[cntI],foreY[cntI], im->gdes[i].col);
+               while (cntI < idxI) {
+                 lastI = cntI;
+                 cntI++;
+                 while ( cntI < idxI && AlmostEqual2sComplement(foreY[lastI],foreY[cntI],4) && AlmostEqual2sComplement(foreY[lastI],foreY[cntI+1],4)){cntI++;} 
+                 gfx_add_point(node,foreX[cntI],foreY[cntI]);
+               }
+               gfx_add_point(node,backX[idxI],backY[idxI]);
+               while (idxI > 1){
+                 lastI = idxI;
+                 idxI--;
+                 while ( idxI > 1 && AlmostEqual2sComplement(backY[lastI], backY[idxI],4) && AlmostEqual2sComplement(backY[lastI],backY[idxI-1],4)){idxI--;} 
+                 gfx_add_point(node,backX[idxI],backY[idxI]);
+               }
+               idxI=-1;
+               drawem = 0;
             }
+            if (drawem != 0){
+              drawem = 0;
+              idxI=-1;
+            }
+            if (ii == im->xsize) break;
+            
+            /* keep things simple for now, just draw these bars
+               do not try to build a big and complex area */
 
-            if ( node != NULL && (ii+1==im->xsize || isnan(im->gdes[i].p_data[ii]) )){
-              /* GF_AREA STACK type*/
-/*
-              if (im->gdes[i].gf == GF_STACK ) {
-*/
-             if ( (im->gdes[i].gf == GF_STACK)
-               || (im->gdes[i].stack) ) {
-                int iii;
-                for (iii=ii-1;iii>area_start;iii--){
-                  gfx_add_point(node,iii+im->xorigin,ytr(im,lastgdes->p_data[iii]));
-                }
-              } else {
-                gfx_add_point(node,ii+im->xorigin,ytr(im,areazero));
-              };
-              node=NULL;
-            };
-          }             
+                                                               
+            if ( im->slopemode == 0 && ii==0){
+                continue;
+            }
+            if ( isnan(im->gdes[i].p_data[ii]) ) {
+                drawem = 1;
+                continue;
+            }
+            ytop = ytr(im,im->gdes[i].p_data[ii]);
+             if ( lastgdes && im->gdes[i].stack ) {
+                  ybase = ytr(im,lastgdes->p_data[ii]);
+            } else {
+                  ybase = ytr(im,areazero);
+            }
+            if ( ybase == ytop ){
+                drawem = 1;
+                continue;        
+            }
+            /* every area has to be wound clock-wise,
+               so we have to make sur base remains base  */                
+            if (ybase > ytop){
+                double extra = ytop;
+                ytop = ybase;
+                ybase = extra;
+            }
+            if ( im->slopemode == 0 ){
+                    backY[++idxI] = ybase-0.2;
+                    backX[idxI] = ii+im->xorigin-1;
+                    foreY[idxI] = ytop+0.2;
+                    foreX[idxI] = ii+im->xorigin-1;
+            }
+            backY[++idxI] = ybase-0.2;
+            backX[idxI] = ii+im->xorigin;
+            foreY[idxI] = ytop+0.2;
+            foreX[idxI] = ii+im->xorigin;
+          }
+          /* close up any remaining area */             
+          free(foreY);
+          free(foreX);
+          free(backY);
+          free(backX);
         } /* else GF_LINE */
       } /* if color != 0x0 */
       /* make sure we do not run into trouble when stacking on NaN */
       for(ii=0;ii<im->xsize;ii++){
         if (isnan(im->gdes[i].p_data[ii])) {
-          if (lastgdes && (im->gdes[i].gf == GF_STACK)) {
+          if (lastgdes && (im->gdes[i].stack)) {
             im->gdes[i].p_data[ii] = lastgdes->p_data[ii];
           } else {
-            im->gdes[i].p_data[ii] =  ytr(im,areazero);
+            im->gdes[i].p_data[ii] = areazero;
           }
         }
       } 
@@ -2500,18 +2871,22 @@ graph_paint(image_desc_t *im, char ***calcpr)
 #ifdef WITH_PIECHART
     case GF_PART:
       if(isnan(im->gdes[i].yrule)) /* fetch variable */
-       im->gdes[i].yrule = im->gdes[im->gdes[i].vidx].vf.val;
+        im->gdes[i].yrule = im->gdes[im->gdes[i].vidx].vf.val;
      
-      if (finite(im->gdes[i].yrule)) { /* even the fetched var can be NaN */
-       pie_part(im,im->gdes[i].col,
-               im->pie_x,im->pie_y,im->piesize*0.4,
-               M_PI*2.0*PieStart/100.0,
-               M_PI*2.0*(PieStart+im->gdes[i].yrule)/100.0);
-       PieStart += im->gdes[i].yrule;
+      if (finite(im->gdes[i].yrule)) {        /* even the fetched var can be NaN */
+        pie_part(im,im->gdes[i].col,
+                im->pie_x,im->pie_y,im->piesize*0.4,
+                M_PI*2.0*PieStart/100.0,
+                M_PI*2.0*(PieStart+im->gdes[i].yrule)/100.0);
+        PieStart += im->gdes[i].yrule;
       }
       break;
 #endif
-       
+    case GF_STACK:
+      rrd_set_error("STACK should already be turned into LINE or AREA here");
+      return -1;
+      break;
+        
     } /* switch */
   }
 #ifdef WITH_PIECHART
@@ -2521,21 +2896,20 @@ graph_paint(image_desc_t *im, char ***calcpr)
   }
 #endif
 
-  if( !(im->extra_flags & ONLY_GRAPH) )  
-      axis_paint(im);
 
   /* grid_paint also does the text */
   if( !(im->extra_flags & ONLY_GRAPH) )  
     grid_paint(im);
+
+  
+  if( !(im->extra_flags & ONLY_GRAPH) )  
+      axis_paint(im);
   
   /* the RULES are the last thing to paint ... */
   for(i=0;i<im->gdes_c;i++){    
     
     switch(im->gdes[i].gf){
     case GF_HRULE:
-      if(isnan(im->gdes[i].yrule)) { /* fetch variable */
-        im->gdes[i].yrule = im->gdes[im->gdes[i].vidx].vf.val;
-      };
       if(im->gdes[i].yrule >= im->minval
          && im->gdes[i].yrule <= im->maxval)
         gfx_new_line(im->canvas,
@@ -2544,9 +2918,6 @@ graph_paint(image_desc_t *im, char ***calcpr)
                      1.0,im->gdes[i].col); 
       break;
     case GF_VRULE:
-      if(im->gdes[i].xrule == 0) { /* fetch variable */
-        im->gdes[i].xrule = im->gdes[im->gdes[i].vidx].vf.when;
-      };
       if(im->gdes[i].xrule >= im->start
          && im->gdes[i].xrule <= im->end)
         gfx_new_line(im->canvas,
@@ -2562,7 +2933,7 @@ graph_paint(image_desc_t *im, char ***calcpr)
   
   if (strcmp(im->graphfile,"-")==0) {
     fo = im->graphhandle ? im->graphhandle : stdout;
-#ifdef WIN32
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
     /* Change translation mode for stdout to BINARY */
     _setmode( _fileno( fo ), O_BINARY );
 #endif
@@ -2573,7 +2944,7 @@ graph_paint(image_desc_t *im, char ***calcpr)
       return (-1);
     }
   }
-  gfx_render (im->canvas,im->ximg,im->yimg,0x0,fo);
+  gfx_render (im->canvas,im->ximg,im->yimg,0x00000000,fo);
   if (strcmp(im->graphfile,"-") != 0)
     fclose(fo);
   return 0;
@@ -2589,17 +2960,21 @@ gdes_alloc(image_desc_t *im){
 
     im->gdes_c++;
     if ((im->gdes = (graph_desc_t *) rrd_realloc(im->gdes, (im->gdes_c)
-                                          * sizeof(graph_desc_t)))==NULL){
-       rrd_set_error("realloc graph_descs");
-       return -1;
+                                           * sizeof(graph_desc_t)))==NULL){
+        rrd_set_error("realloc graph_descs");
+        return -1;
     }
 
 
     im->gdes[im->gdes_c-1].step=im->step;
+    im->gdes[im->gdes_c-1].step_orig=im->step;
     im->gdes[im->gdes_c-1].stack=0;
+    im->gdes[im->gdes_c-1].linewidth=0;
     im->gdes[im->gdes_c-1].debug=0;
     im->gdes[im->gdes_c-1].start=im->start; 
+    im->gdes[im->gdes_c-1].start_orig=im->start; 
     im->gdes[im->gdes_c-1].end=im->end; 
+    im->gdes[im->gdes_c-1].end_orig=im->end; 
     im->gdes[im->gdes_c-1].vname[0]='\0'; 
     im->gdes[im->gdes_c-1].data=NULL;
     im->gdes[im->gdes_c-1].ds_namv=NULL;
@@ -2610,8 +2985,11 @@ gdes_alloc(image_desc_t *im){
     im->gdes[im->gdes_c-1].col = 0x0;
     im->gdes[im->gdes_c-1].legend[0]='\0';
     im->gdes[im->gdes_c-1].format[0]='\0';
+    im->gdes[im->gdes_c-1].strftm=0;   
     im->gdes[im->gdes_c-1].rrd[0]='\0';
     im->gdes[im->gdes_c-1].ds=-1;    
+    im->gdes[im->gdes_c-1].cf_reduce=CF_AVERAGE;    
+    im->gdes[im->gdes_c-1].cf=CF_AVERAGE;    
     im->gdes[im->gdes_c-1].p_data=NULL;    
     im->gdes[im->gdes_c-1].yrule=DNAN;
     im->gdes[im->gdes_c-1].xrule=0;
@@ -2621,22 +2999,22 @@ gdes_alloc(image_desc_t *im){
 /* copies input untill the first unescaped colon is found
    or until input ends. backslashes have to be escaped as well */
 int
-scan_for_col(char *input, int len, char *output)
+scan_for_col(const char *const input, int len, char *const output)
 {
     int inp,outp=0;
     for (inp=0; 
-        inp < len &&
-          input[inp] != ':' &&
-          input[inp] != '\0';
-        inp++){
+         inp < len &&
+           input[inp] != ':' &&
+           input[inp] != '\0';
+         inp++){
       if (input[inp] == '\\' &&
-         input[inp+1] != '\0' && 
-         (input[inp+1] == '\\' ||
-          input[inp+1] == ':')){
-       output[outp++] = input[++inp];
+          input[inp+1] != '\0' && 
+          (input[inp+1] == '\\' ||
+           input[inp+1] == ':')){
+        output[outp++] = input[++inp];
       }
       else {
-       output[outp++] = input[inp];
+        output[outp++] = input[inp];
       }
     }
     output[outp] = '\0';
@@ -2652,36 +3030,35 @@ int
 rrd_graph(int argc, char **argv, char ***prdata, int *xsize, int *ysize, FILE *stream, double *ymin, double *ymax)
 {
     image_desc_t   im;
-            
     rrd_graph_init(&im);
     im.graphhandle = stream;
     
     rrd_graph_options(argc,argv,&im);
     if (rrd_test_error()) {
-       im_free(&im);
-       return -1;
+        im_free(&im);
+        return -1;
     }
     
     if (strlen(argv[optind])>=MAXPATH) {
-       rrd_set_error("filename (including path) too long");
-       im_free(&im);
-       return -1;
+        rrd_set_error("filename (including path) too long");
+        im_free(&im);
+        return -1;
     }
     strncpy(im.graphfile,argv[optind],MAXPATH-1);
     im.graphfile[MAXPATH-1]='\0';
 
     rrd_graph_script(argc,argv,&im,1);
     if (rrd_test_error()) {
-       im_free(&im);
-       return -1;
+        im_free(&im);
+        return -1;
     }
 
     /* Everything is now read and the actual work can start */
 
     (*prdata)=NULL;
     if (graph_paint(&im,prdata)==-1){
-       im_free(&im);
-       return -1;
+        im_free(&im);
+        return -1;
     }
 
     /* The image is generated and needs to be output.
@@ -2693,26 +3070,26 @@ rrd_graph(int argc, char **argv, char ***prdata, int *xsize, int *ysize, FILE *s
     *ymin=im.minval;
     *ymax=im.maxval;
     if (im.imginfo) {
-       char *filename;
-       if (!(*prdata)) {
-           /* maybe prdata is not allocated yet ... lets do it now */
-           if ((*prdata = calloc(2,sizeof(char *)))==NULL) {
-               rrd_set_error("malloc imginfo");
-               return -1; 
-           };
-       }
-       if(((*prdata)[0] = malloc((strlen(im.imginfo)+200+strlen(im.graphfile))*sizeof(char)))
-        ==NULL){
-           rrd_set_error("malloc imginfo");
-           return -1;
-       }
-       filename=im.graphfile+strlen(im.graphfile);
-       while(filename > im.graphfile) {
-           if (*(filename-1)=='/' || *(filename-1)=='\\' ) break;
-           filename--;
-       }
+        char *filename;
+        if (!(*prdata)) {
+            /* maybe prdata is not allocated yet ... lets do it now */
+            if ((*prdata = calloc(2,sizeof(char *)))==NULL) {
+                rrd_set_error("malloc imginfo");
+                return -1; 
+            };
+        }
+        if(((*prdata)[0] = malloc((strlen(im.imginfo)+200+strlen(im.graphfile))*sizeof(char)))
+         ==NULL){
+            rrd_set_error("malloc imginfo");
+            return -1;
+        }
+        filename=im.graphfile+strlen(im.graphfile);
+        while(filename > im.graphfile) {
+            if (*(filename-1)=='/' || *(filename-1)=='\\' ) break;
+            filename--;
+        }
 
-       sprintf((*prdata)[0],im.imginfo,filename,(long)(im.canvas->zoom*im.ximg),(long)(im.canvas->zoom*im.yimg));
+        sprintf((*prdata)[0],im.imginfo,filename,(long)(im.canvas->zoom*im.ximg),(long)(im.canvas->zoom*im.yimg));
     }
     im_free(&im);
     return 0;
@@ -2728,8 +3105,13 @@ rrd_graph_init(image_desc_t *im)
 #endif
 #ifdef HAVE_SETLOCALE
     setlocale(LC_TIME,"");
+#ifdef HAVE_MBSTOWCS
+    setlocale(LC_CTYPE,"");
 #endif
-
+#endif
+    im->yorigin=0;
+    im->xorigin=0;
+    im->minval=0;
     im->xlab_user.minsec = -1;
     im->ximg=0;
     im->yimg=0;
@@ -2738,14 +3120,20 @@ rrd_graph_init(image_desc_t *im)
     im->step = 0;
     im->ylegend[0] = '\0';
     im->title[0] = '\0';
+    im->watermark[0] = '\0';
     im->minval = DNAN;
     im->maxval = DNAN;    
     im->unitsexponent= 9999;
+    im->unitslength= 6; 
+    im->forceleftspace = 0;
+    im->symbol = ' ';
+    im->viewfactor = 1.0;
     im->extra_flags= 0;
     im->rigid = 0;
     im->gridfit = 1;
     im->imginfo = NULL;
     im->lazy = 0;
+    im->slopemode = 0;
     im->logarithmic = 0;
     im->ygridstep = DNAN;
     im->draw_x_grid = 1;
@@ -2761,19 +3149,35 @@ rrd_graph_init(image_desc_t *im)
     
     for(i=0;i<DIM(graph_col);i++)
         im->graph_col[i]=graph_col[i];
-#ifdef WIN32
+
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
     {
             char *windir; 
+            char rrd_win_default_font[1000];
             windir = getenv("windir");
             /* %windir% is something like D:\windows or C:\winnt */
             if (windir != NULL) {
-                    strcpy(rrd_win_default_font,windir);
-                    strcat(rrd_win_default_font,"\\fonts\\cour.ttf");
-                    for(i=0;i<DIM(text_prop);i++)
-                            strcpy(text_prop[i].font,rrd_win_default_font);
-            }
+                    strncpy(rrd_win_default_font,windir,500);
+                    rrd_win_default_font[500] = '\0';
+                    strcat(rrd_win_default_font,"\\fonts\\");
+                    strcat(rrd_win_default_font,RRD_DEFAULT_FONT);         
+                    for(i=0;i<DIM(text_prop);i++){
+                            strncpy(text_prop[i].font,rrd_win_default_font,sizeof(text_prop[i].font)-1);
+                            text_prop[i].font[sizeof(text_prop[i].font)-1] = '\0';
+                     }
+             }
     }
 #endif
+    {
+            char *deffont; 
+            deffont = getenv("RRD_DEFAULT_FONT");
+            if (deffont != NULL) {
+                 for(i=0;i<DIM(text_prop);i++){
+                        strncpy(text_prop[i].font,deffont,sizeof(text_prop[i].font)-1);
+                        text_prop[i].font[sizeof(text_prop[i].font)-1] = '\0';
+                 }
+            }
+    }
     for(i=0;i<DIM(text_prop);i++){        
       im->text_prop[i].size = text_prop[i].size;
       strcpy(im->text_prop[i].font,text_prop[i].font);
@@ -2783,231 +3187,294 @@ rrd_graph_init(image_desc_t *im)
 void
 rrd_graph_options(int argc, char *argv[],image_desc_t *im)
 {
-    int                        stroff;    
-    char               *parsetime_error = NULL;
-    char               scan_gtm[12],scan_mtm[12],scan_ltm[12],col_nam[12];
-    time_t             start_tmp=0,end_tmp=0;
-    long               long_tmp;
-    struct rrd_time_value      start_tv, end_tv;
+    int                        stroff;    
+    char                *parsetime_error = NULL;
+    char                scan_gtm[12],scan_mtm[12],scan_ltm[12],col_nam[12];
+    time_t                start_tmp=0,end_tmp=0;
+    long                long_tmp;
+    struct rrd_time_value        start_tv, end_tv;
     gfx_color_t         color;
+    optind = 0; opterr = 0;  /* initialize getopt */
 
     parsetime("end-24h", &start_tv);
     parsetime("now", &end_tv);
 
+    /* defines for long options without a short equivalent. should be bytes,
+       and may not collide with (the ASCII value of) short options */
+    #define LONGOPT_UNITS_SI 255
+
     while (1){
-       static struct option long_options[] =
-       {
-           {"start",      required_argument, 0,  's'},
-           {"end",        required_argument, 0,  'e'},
-           {"x-grid",     required_argument, 0,  'x'},
-           {"y-grid",     required_argument, 0,  'y'},
-           {"vertical-label",required_argument,0,'v'},
-           {"width",      required_argument, 0,  'w'},
-           {"height",     required_argument, 0,  'h'},
-           {"interlaced", no_argument,       0,  'i'},
-           {"upper-limit",required_argument, 0,  'u'},
-           {"lower-limit",required_argument, 0,  'l'},
-           {"rigid",      no_argument,       0,  'r'},
-           {"base",       required_argument, 0,  'b'},
-           {"logarithmic",no_argument,       0,  'o'},
-           {"color",      required_argument, 0,  'c'},
+        static struct option long_options[] =
+        {
+            {"start",      required_argument, 0,  's'},
+            {"end",        required_argument, 0,  'e'},
+            {"x-grid",     required_argument, 0,  'x'},
+            {"y-grid",     required_argument, 0,  'y'},
+            {"vertical-label",required_argument,0,'v'},
+            {"width",      required_argument, 0,  'w'},
+            {"height",     required_argument, 0,  'h'},
+            {"interlaced", no_argument,       0,  'i'},
+            {"upper-limit",required_argument, 0,  'u'},
+            {"lower-limit",required_argument, 0,  'l'},
+            {"rigid",      no_argument,       0,  'r'},
+            {"base",       required_argument, 0,  'b'},
+            {"logarithmic",no_argument,       0,  'o'},
+            {"color",      required_argument, 0,  'c'},
             {"font",       required_argument, 0,  'n'},
-           {"title",      required_argument, 0,  't'},
-           {"imginfo",    required_argument, 0,  'f'},
-           {"imgformat",  required_argument, 0,  'a'},
-           {"lazy",       no_argument,       0,  'z'},
+            {"title",      required_argument, 0,  't'},
+            {"imginfo",    required_argument, 0,  'f'},
+            {"imgformat",  required_argument, 0,  'a'},
+            {"lazy",       no_argument,       0,  'z'},
             {"zoom",       required_argument, 0,  'm'},
-           {"no-legend",  no_argument,       0,  'g'},
-           {"force-rules-legend",no_argument,0,  'F'},
+            {"no-legend",  no_argument,       0,  'g'},
+            {"force-rules-legend",no_argument,0,  'F'},
             {"only-graph", no_argument,       0,  'j'},
-           {"alt-y-grid", no_argument,       0,  'Y'},
+            {"alt-y-grid", no_argument,       0,  'Y'},
             {"no-minor",   no_argument,       0,  'I'},
-           {"alt-autoscale", no_argument,    0,  'A'},
-           {"alt-autoscale-max", no_argument, 0, 'M'},
-           {"units-exponent",required_argument, 0, 'X'},
-           {"step",       required_argument, 0,    'S'},
+            {"slope-mode", no_argument,              0,  'E'},
+            {"alt-autoscale", no_argument,    0,  'A'},
+           {"alt-autoscale-min", no_argument, 0, 'J'},
+            {"alt-autoscale-max", no_argument, 0, 'M'},
+            {"no-gridfit", no_argument,       0,   'N'},
+            {"units-exponent",required_argument, 0, 'X'},
+            {"units-length",required_argument, 0, 'L'},
+            {"units",      required_argument, 0,  LONGOPT_UNITS_SI },
+            {"step",       required_argument, 0,    'S'},
             {"tabwidth",   required_argument, 0,    'T'},            
-           {"no-gridfit", no_argument,       0,   'N'},
-           {0,0,0,0}};
-       int option_index = 0;
-       int opt;
-
-
-       opt = getopt_long(argc, argv, 
-                        "s:e:x:y:v:w:h:iu:l:rb:oc:n:m:t:f:a:I:zgjFYAMX:S:NT:",
-                         long_options, &option_index);
-
-       if (opt == EOF)
-           break;
-       
-       switch(opt) {
+            {"font-render-mode", required_argument, 0, 'R'},
+            {"font-smoothing-threshold", required_argument, 0, 'B'},
+            {"watermark",  required_argument, 0,  'W'},
+            {"alt-y-mrtg", no_argument,       0,  1000}, /* this has no effect it is just here to save old apps from crashing when they use it */
+            {0,0,0,0}};
+        int option_index = 0;
+        int opt;
+        int col_start,col_end;
+
+        opt = getopt_long(argc, argv, 
+                         "s:e:x:y:v:w:h:iu:l:rb:oc:n:m:t:f:a:I:zgjFYAMEX:L:S:T:NR:B:W:",
+                          long_options, &option_index);
+
+        if (opt == EOF)
+            break;
+        
+        switch(opt) {
         case 'I':
             im->extra_flags |= NOMINOR;
             break;
-       case 'Y':
-           im->extra_flags |= ALTYGRID;
-           break;
-       case 'A':
-           im->extra_flags |= ALTAUTOSCALE;
-           break;
-       case 'M':
-           im->extra_flags |= ALTAUTOSCALE_MAX;
+        case 'Y':
+            im->extra_flags |= ALTYGRID;
+            break;
+        case 'A':
+            im->extra_flags |= ALTAUTOSCALE;
            break;
+       case 'J':
+           im->extra_flags |= ALTAUTOSCALE_MIN;
+            break;
+        case 'M':
+            im->extra_flags |= ALTAUTOSCALE_MAX;
+            break;
         case 'j':
            im->extra_flags |= ONLY_GRAPH;
            break;
-       case 'g':
-           im->extra_flags |= NOLEGEND;
-           break;
-       case 'F':
-           im->extra_flags |= FORCE_RULES_LEGEND;
-           break;
-       case 'X':
-           im->unitsexponent = atoi(optarg);
-           break;
-       case 'T':
-           im->tabwidth = atof(optarg);
-           break;
-       case 'S':
-           im->step =  atoi(optarg);
-           break;
-       case 262:
-           im->gridfit = 0;
-           break;
-       case 's':
-           if ((parsetime_error = parsetime(optarg, &start_tv))) {
-               rrd_set_error( "start time: %s", parsetime_error );
-               return;
-           }
-           break;
-       case 'e':
-           if ((parsetime_error = parsetime(optarg, &end_tv))) {
-               rrd_set_error( "end time: %s", parsetime_error );
-               return;
-           }
-           break;
-       case 'x':
-           if(strcmp(optarg,"none") == 0){
-             im->draw_x_grid=0;
-             break;
-           };
-               
-           if(sscanf(optarg,
-                     "%10[A-Z]:%ld:%10[A-Z]:%ld:%10[A-Z]:%ld:%ld:%n",
-                     scan_gtm,
-                     &im->xlab_user.gridst,
-                     scan_mtm,
-                     &im->xlab_user.mgridst,
-                     scan_ltm,
-                     &im->xlab_user.labst,
-                     &im->xlab_user.precis,
-                     &stroff) == 7 && stroff != 0){
+        case 'g':
+            im->extra_flags |= NOLEGEND;
+            break;
+        case 'F':
+            im->extra_flags |= FORCE_RULES_LEGEND;
+            break;
+        case LONGOPT_UNITS_SI:
+            if(im->extra_flags & FORCE_UNITS) {
+                rrd_set_error("--units can only be used once!");
+                return;
+            }
+            if(strcmp(optarg,"si")==0)
+                im->extra_flags |= FORCE_UNITS_SI;
+            else {
+                rrd_set_error("invalid argument for --units: %s", optarg );
+                return;
+            }
+            break;
+        case 'X':
+            im->unitsexponent = atoi(optarg);
+            break;
+        case 'L':
+            im->unitslength = atoi(optarg);
+            im->forceleftspace = 1;
+            break;
+        case 'T':
+            im->tabwidth = atof(optarg);
+            break;
+        case 'S':
+            im->step =  atoi(optarg);
+            break;
+        case 'N':
+            im->gridfit = 0;
+            break;
+        case 's':
+            if ((parsetime_error = parsetime(optarg, &start_tv))) {
+                rrd_set_error( "start time: %s", parsetime_error );
+                return;
+            }
+            break;
+        case 'e':
+            if ((parsetime_error = parsetime(optarg, &end_tv))) {
+                rrd_set_error( "end time: %s", parsetime_error );
+                return;
+            }
+            break;
+        case 'x':
+            if(strcmp(optarg,"none") == 0){
+              im->draw_x_grid=0;
+              break;
+            };
+                
+            if(sscanf(optarg,
+                      "%10[A-Z]:%ld:%10[A-Z]:%ld:%10[A-Z]:%ld:%ld:%n",
+                      scan_gtm,
+                      &im->xlab_user.gridst,
+                      scan_mtm,
+                      &im->xlab_user.mgridst,
+                      scan_ltm,
+                      &im->xlab_user.labst,
+                      &im->xlab_user.precis,
+                      &stroff) == 7 && stroff != 0){
                 strncpy(im->xlab_form, optarg+stroff, sizeof(im->xlab_form) - 1);
-               if((int)(im->xlab_user.gridtm = tmt_conv(scan_gtm)) == -1){
-                   rrd_set_error("unknown keyword %s",scan_gtm);
-                   return;
-               } else if ((int)(im->xlab_user.mgridtm = tmt_conv(scan_mtm)) == -1){
-                   rrd_set_error("unknown keyword %s",scan_mtm);
-                   return;
-               } else if ((int)(im->xlab_user.labtm = tmt_conv(scan_ltm)) == -1){
-                   rrd_set_error("unknown keyword %s",scan_ltm);
-                   return;
-               } 
-               im->xlab_user.minsec = 1;
-               im->xlab_user.stst = im->xlab_form;
-           } else {
-               rrd_set_error("invalid x-grid format");
-               return;
-           }
-           break;
-       case 'y':
-
-           if(strcmp(optarg,"none") == 0){
-             im->draw_y_grid=0;
-             break;
-           };
-
-           if(sscanf(optarg,
-                     "%lf:%d",
-                     &im->ygridstep,
-                     &im->ylabfact) == 2) {
-               if(im->ygridstep<=0){
-                   rrd_set_error("grid step must be > 0");
-                   return;
-               } else if (im->ylabfact < 1){
-                   rrd_set_error("label factor must be > 0");
-                   return;
-               } 
-           } else {
-               rrd_set_error("invalid y-grid format");
-               return;
-           }
-           break;
-       case 'v':
-           strncpy(im->ylegend,optarg,150);
-           im->ylegend[150]='\0';
-           break;
-       case 'u':
-           im->maxval = atof(optarg);
-           break;
-       case 'l':
-           im->minval = atof(optarg);
-           break;
-       case 'b':
-           im->base = atol(optarg);
-           if(im->base != 1024 && im->base != 1000 ){
-               rrd_set_error("the only sensible value for base apart from 1000 is 1024");
-               return;
-           }
-           break;
-       case 'w':
-           long_tmp = atol(optarg);
-           if (long_tmp < 10) {
-               rrd_set_error("width below 10 pixels");
-               return;
-           }
-           im->xsize = long_tmp;
-           break;
-       case 'h':
-           long_tmp = atol(optarg);
-           if (long_tmp < 10) {
-               rrd_set_error("height below 10 pixels");
-               return;
-           }
-           im->ysize = long_tmp;
-           break;
-       case 'i':
-           im->canvas->interlaced = 1;
-           break;
-       case 'r':
-           im->rigid = 1;
-           break;
-       case 'f':
-           im->imginfo = optarg;
-           break;
-       case 'a':
-           if((int)(im->canvas->imgformat = if_conv(optarg)) == -1) {
-               rrd_set_error("unsupported graphics format '%s'",optarg);
-               return;
-           }
-           break;
-       case 'z':
-           im->lazy = 1;
-           break;
-       case 'o':
-           im->logarithmic = 1;
-           if (isnan(im->minval))
-               im->minval=1;
-           break;
+                im->xlab_form[sizeof(im->xlab_form)-1] = '\0'; 
+                if((int)(im->xlab_user.gridtm = tmt_conv(scan_gtm)) == -1){
+                    rrd_set_error("unknown keyword %s",scan_gtm);
+                    return;
+                } else if ((int)(im->xlab_user.mgridtm = tmt_conv(scan_mtm)) == -1){
+                    rrd_set_error("unknown keyword %s",scan_mtm);
+                    return;
+                } else if ((int)(im->xlab_user.labtm = tmt_conv(scan_ltm)) == -1){
+                    rrd_set_error("unknown keyword %s",scan_ltm);
+                    return;
+                } 
+                im->xlab_user.minsec = 1;
+                im->xlab_user.stst = im->xlab_form;
+            } else {
+                rrd_set_error("invalid x-grid format");
+                return;
+            }
+            break;
+        case 'y':
+
+            if(strcmp(optarg,"none") == 0){
+              im->draw_y_grid=0;
+              break;
+            };
+
+            if(sscanf(optarg,
+                      "%lf:%d",
+                      &im->ygridstep,
+                      &im->ylabfact) == 2) {
+                if(im->ygridstep<=0){
+                    rrd_set_error("grid step must be > 0");
+                    return;
+                } else if (im->ylabfact < 1){
+                    rrd_set_error("label factor must be > 0");
+                    return;
+                } 
+            } else {
+                rrd_set_error("invalid y-grid format");
+                return;
+            }
+            break;
+        case 'v':
+            strncpy(im->ylegend,optarg,150);
+            im->ylegend[150]='\0';
+            break;
+        case 'u':
+            im->maxval = atof(optarg);
+            break;
+        case 'l':
+            im->minval = atof(optarg);
+            break;
+        case 'b':
+            im->base = atol(optarg);
+            if(im->base != 1024 && im->base != 1000 ){
+                rrd_set_error("the only sensible value for base apart from 1000 is 1024");
+                return;
+            }
+            break;
+        case 'w':
+            long_tmp = atol(optarg);
+            if (long_tmp < 10) {
+                rrd_set_error("width below 10 pixels");
+                return;
+            }
+            im->xsize = long_tmp;
+            break;
+        case 'h':
+            long_tmp = atol(optarg);
+            if (long_tmp < 10) {
+                rrd_set_error("height below 10 pixels");
+                return;
+            }
+            im->ysize = long_tmp;
+            break;
+        case 'i':
+            im->canvas->interlaced = 1;
+            break;
+        case 'r':
+            im->rigid = 1;
+            break;
+        case 'f':
+            im->imginfo = optarg;
+            break;
+            case 'a':
+            if((int)(im->canvas->imgformat = if_conv(optarg)) == -1) {
+                rrd_set_error("unsupported graphics format '%s'",optarg);
+                return;
+            }
+            break;
+        case 'z':
+            im->lazy = 1;
+            break;
+        case 'E':
+            im->slopemode = 1;
+            break;
+
+        case 'o':
+            im->logarithmic = 1;
+            break;
         case 'c':
             if(sscanf(optarg,
-                      "%10[A-Z]#%8lx",
-                      col_nam,&color) == 2){
+                      "%10[A-Z]#%n%8lx%n",
+                      col_nam,&col_start,&color,&col_end) == 2){
                 int ci;
+                int col_len = col_end - col_start;
+                switch (col_len){
+                        case 3:
+                                color = (
+                                        ((color & 0xF00) * 0x110000) |
+                                        ((color & 0x0F0) * 0x011000) |
+                                        ((color & 0x00F) * 0x001100) |
+                                        0x000000FF
+                                        );
+                                break;
+                        case 4:
+                                color = (
+                                        ((color & 0xF000) * 0x11000) |
+                                        ((color & 0x0F00) * 0x01100) |
+                                        ((color & 0x00F0) * 0x00110) |
+                                        ((color & 0x000F) * 0x00011)
+                                        );
+                                break;
+                        case 6:
+                                color = (color << 8) + 0xff /* shift left by 8 */;
+                                break;
+                        case 8:
+                                break;
+                        default:
+                                rrd_set_error("the color format is #RRGGBB[AA]");
+                                return;
+                }
                 if((ci=grc_conv(col_nam)) != -1){
                     im->graph_col[ci]=color;
                 }  else {
                   rrd_set_error("invalid color name '%s'",col_nam);
+                  return;
                 }
             } else {
                 rrd_set_error("invalid color def format");
@@ -3015,56 +3482,76 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im)
             }
             break;        
         case 'n':{
-           char prop[15];
-           double size = 1;
-           char font[1024];
-
-           if(sscanf(optarg,
-                               "%10[A-Z]:%lf:%1000s",
-                               prop,&size,font) == 3){
-               int sindex;
-               if((sindex=text_prop_conv(prop)) != -1){
-                   im->text_prop[sindex].size=size;              
-                   strcpy(im->text_prop[sindex].font,font);
-                   if (sindex==0) { /* the default */
-                       im->text_prop[TEXT_PROP_TITLE].size=size;
-                       strcpy(im->text_prop[TEXT_PROP_TITLE].font,font);
-                       im->text_prop[TEXT_PROP_AXIS].size=size;
-                       strcpy(im->text_prop[TEXT_PROP_AXIS].font,font);
-                       im->text_prop[TEXT_PROP_UNIT].size=size;
-                       strcpy(im->text_prop[TEXT_PROP_UNIT].font,font);
-                       im->text_prop[TEXT_PROP_LEGEND].size=size;
-                       strcpy(im->text_prop[TEXT_PROP_LEGEND].font,font);
-                   }
-               } else {
-                   rrd_set_error("invalid fonttag '%s'",prop);
-                   return;
-               }
-           } else {
-               rrd_set_error("invalid text property format");
-               return;
-           }
-           break;          
-       }
+            char prop[15];
+            double size = 1;
+            char font[1024] = "";
+
+            if(sscanf(optarg,
+                                "%10[A-Z]:%lf:%1000s",
+                                prop,&size,font) >= 2){
+                int sindex,propidx;
+                if((sindex=text_prop_conv(prop)) != -1){
+                  for (propidx=sindex;propidx<TEXT_PROP_LAST;propidx++){                        
+                        if (size > 0){
+                              im->text_prop[propidx].size=size;              
+                      }
+                       if (strlen(font) > 0){
+                          strcpy(im->text_prop[propidx].font,font);
+                      }
+                      if (propidx==sindex && sindex != 0) break;
+                  }
+                } else {
+                    rrd_set_error("invalid fonttag '%s'",prop);
+                    return;
+                }
+            } else {
+                rrd_set_error("invalid text property format");
+                return;
+            }
+            break;          
+        }
         case 'm':
-           im->canvas->zoom = atof(optarg);
-           if (im->canvas->zoom <= 0.0) {
-               rrd_set_error("zoom factor must be > 0");
-               return;
-           }
+            im->canvas->zoom = atof(optarg);
+            if (im->canvas->zoom <= 0.0) {
+                rrd_set_error("zoom factor must be > 0");
+                return;
+            }
           break;
-       case 't':
-           strncpy(im->title,optarg,150);
-           im->title[150]='\0';
-           break;
+        case 't':
+            strncpy(im->title,optarg,150);
+            im->title[150]='\0';
+            break;
+
+        case 'R':
+                if ( strcmp( optarg, "normal" ) == 0 )
+                        im->canvas->aa_type = AA_NORMAL;
+                else if ( strcmp( optarg, "light" ) == 0 )
+                        im->canvas->aa_type = AA_LIGHT;
+                else if ( strcmp( optarg, "mono" ) == 0 )
+                        im->canvas->aa_type = AA_NONE;
+                else
+                {
+                        rrd_set_error("unknown font-render-mode '%s'", optarg );
+                        return;
+                }
+                break;
 
-       case '?':
+        case 'B':
+            im->canvas->font_aa_threshold = atof(optarg);
+                break;
+
+        case 'W':
+            strncpy(im->watermark,optarg,100);
+            im->watermark[99]='\0';
+            break;
+
+        case '?':
             if (optopt != 0)
                 rrd_set_error("unknown option '%c'", optopt);
             else
                 rrd_set_error("unknown option '%s'",argv[optind-1]);
             return;
-       }
+        }
     }
     
     if (optind >= argc) {
@@ -3072,25 +3559,25 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im)
        return;
     }
 
-    if (im->logarithmic == 1 && (im->minval <= 0 || isnan(im->minval))){
-       rrd_set_error("for a logarithmic yaxis you must specify a lower-limit > 0");    
-       return;
+    if (im->logarithmic == 1 && im->minval <= 0){
+        rrd_set_error("for a logarithmic yaxis you must specify a lower-limit > 0");        
+        return;
     }
 
     if (proc_start_end(&start_tv,&end_tv,&start_tmp,&end_tmp) == -1){
-       /* error string is set in parsetime.c */
-       return;
+        /* error string is set in parsetime.c */
+        return;
     }  
     
     if (start_tmp < 3600*24*365*10){
-       rrd_set_error("the first entry to fetch should be after 1980 (%ld)",start_tmp);
-       return;
+        rrd_set_error("the first entry to fetch should be after 1980 (%ld)",start_tmp);
+        return;
     }
     
     if (end_tmp < start_tmp) {
-       rrd_set_error("start (%ld) should be less than end (%ld)", 
-              start_tmp, end_tmp);
-       return;
+        rrd_set_error("start (%ld) should be less than end (%ld)", 
+               start_tmp, end_tmp);
+        return;
     }
     
     im->start = start_tmp;
@@ -3098,15 +3585,6 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im)
     im->step = max((long)im->step, (im->end-im->start)/im->xsize);
 }
 
-int
-rrd_graph_check_vname(image_desc_t *im, char *varname, char *err)
-{
-    if ((im->gdes[im->gdes_c-1].vidx=find_var(im,varname))==-1) {
-       rrd_set_error("Unknown variable '%s' in %s",varname,err);
-       return -1;
-    }
-    return 0;
-}
 int
 rrd_graph_color(image_desc_t *im, char *var, char *err, int optional)
 {
@@ -3115,37 +3593,37 @@ rrd_graph_color(image_desc_t *im, char *var, char *err, int optional)
 
     color=strstr(var,"#");
     if (color==NULL) {
-       if (optional==0) {
-           rrd_set_error("Found no color in %s",err);
-           return 0;
-       }
-       return 0;
+        if (optional==0) {
+            rrd_set_error("Found no color in %s",err);
+            return 0;
+        }
+        return 0;
     } else {
-       int n=0;
-       char *rest;
-       gfx_color_t    col;
-
-       rest=strstr(color,":");
-       if (rest!=NULL)
-           n=rest-color;
-       else
-           n=strlen(color);
-
-       switch (n) {
-           case 7:
-               sscanf(color,"#%6lx%n",&col,&n);
+        int n=0;
+        char *rest;
+        gfx_color_t    col;
+
+        rest=strstr(color,":");
+        if (rest!=NULL)
+            n=rest-color;
+        else
+            n=strlen(color);
+
+        switch (n) {
+            case 7:
+                sscanf(color,"#%6lx%n",&col,&n);
                 col = (col << 8) + 0xff /* shift left by 8 */;
-               if (n!=7) rrd_set_error("Color problem in %s",err);
-               break;
-           case 9:
-               sscanf(color,"#%8lx%n",&col,&n);
-               if (n==9) break;
-           default:
-               rrd_set_error("Color problem in %s",err);
-       }
-       if (rrd_test_error()) return 0;
-       gdp->col = col;
-       return n;
+                if (n!=7) rrd_set_error("Color problem in %s",err);
+                break;
+            case 9:
+                sscanf(color,"#%8lx%n",&col,&n);
+                if (n==9) break;
+            default:
+                rrd_set_error("Color problem in %s",err);
+        }
+        if (rrd_test_error()) return 0;
+        gdp->col = col;
+        return n;
     }
 }
 
@@ -3163,12 +3641,17 @@ int bad_format(char *fmt) {
              /* '%s', '%S' and '%%' are allowed */
              if (*ptr == 's' || *ptr == 'S' || *ptr == '%') ptr++;
 
+             /* %c is allowed (but use only with vdef!) */
+             else if (*ptr == 'c') {
+                ptr++;
+                n=1;
+             }
+
              /* or else '% 6.2lf' and such are allowed */
              else {
-   
                  /* optional padding character */
                  if (*ptr == ' ' || *ptr == '+' || *ptr == '-') ptr++;
-  
+
                  /* This should take care of 'm.n' with all three optional */
                  while (*ptr >= '0' && *ptr <= '9') ptr++;
                  if (*ptr == '.') ptr++;
@@ -3189,86 +3672,92 @@ int bad_format(char *fmt) {
 int
 vdef_parse(gdes,str)
 struct graph_desc_t *gdes;
-char *str;
+const char *const str;
 {
     /* A VDEF currently is either "func" or "param,func"
      * so the parsing is rather simple.  Change if needed.
      */
-    double     param;
-    char       func[30];
-    int                n;
+    double        param;
+    char        func[30];
+    int                n;
     
     n=0;
     sscanf(str,"%le,%29[A-Z]%n",&param,func,&n);
     if (n== (int)strlen(str)) { /* matched */
-       ;
+        ;
     } else {
-       n=0;
-       sscanf(str,"%29[A-Z]%n",func,&n);
-       if (n== (int)strlen(str)) { /* matched */
-           param=DNAN;
-       } else {
-           rrd_set_error("Unknown function string '%s' in VDEF '%s'"
-               ,str
-               ,gdes->vname
-               );
-           return -1;
-       }
+        n=0;
+        sscanf(str,"%29[A-Z]%n",func,&n);
+        if (n== (int)strlen(str)) { /* matched */
+            param=DNAN;
+        } else {
+            rrd_set_error("Unknown function string '%s' in VDEF '%s'"
+                ,str
+                ,gdes->vname
+                );
+            return -1;
+        }
     }
-    if         (!strcmp("PERCENT",func)) gdes->vf.op = VDEF_PERCENT;
-    else if    (!strcmp("MAXIMUM",func)) gdes->vf.op = VDEF_MAXIMUM;
-    else if    (!strcmp("AVERAGE",func)) gdes->vf.op = VDEF_AVERAGE;
-    else if    (!strcmp("MINIMUM",func)) gdes->vf.op = VDEF_MINIMUM;
-    else if    (!strcmp("TOTAL",  func)) gdes->vf.op = VDEF_TOTAL;
-    else if    (!strcmp("FIRST",  func)) gdes->vf.op = VDEF_FIRST;
-    else if    (!strcmp("LAST",   func)) gdes->vf.op = VDEF_LAST;
+    if                (!strcmp("PERCENT",func)) gdes->vf.op = VDEF_PERCENT;
+    else if        (!strcmp("MAXIMUM",func)) gdes->vf.op = VDEF_MAXIMUM;
+    else if        (!strcmp("AVERAGE",func)) gdes->vf.op = VDEF_AVERAGE;
+    else if        (!strcmp("MINIMUM",func)) gdes->vf.op = VDEF_MINIMUM;
+    else if        (!strcmp("TOTAL",  func)) gdes->vf.op = VDEF_TOTAL;
+    else if        (!strcmp("FIRST",  func)) gdes->vf.op = VDEF_FIRST;
+    else if        (!strcmp("LAST",   func)) gdes->vf.op = VDEF_LAST;
+    else if     (!strcmp("LSLSLOPE", func)) gdes->vf.op = VDEF_LSLSLOPE;
+    else if     (!strcmp("LSLINT",   func)) gdes->vf.op = VDEF_LSLINT;
+    else if     (!strcmp("LSLCORREL",func)) gdes->vf.op = VDEF_LSLCORREL;
     else {
-       rrd_set_error("Unknown function '%s' in VDEF '%s'\n"
-           ,func
-           ,gdes->vname
-           );
-       return -1;
+        rrd_set_error("Unknown function '%s' in VDEF '%s'\n"
+            ,func
+            ,gdes->vname
+            );
+        return -1;
     };
 
     switch (gdes->vf.op) {
-       case VDEF_PERCENT:
-           if (isnan(param)) { /* no parameter given */
-               rrd_set_error("Function '%s' needs parameter in VDEF '%s'\n"
-                   ,func
-                   ,gdes->vname
-                   );
-               return -1;
-           };
-           if (param>=0.0 && param<=100.0) {
-               gdes->vf.param = param;
-               gdes->vf.val   = DNAN;  /* undefined */
-               gdes->vf.when  = 0;     /* undefined */
-           } else {
-               rrd_set_error("Parameter '%f' out of range in VDEF '%s'\n"
-                   ,param
-                   ,gdes->vname
-                   );
-               return -1;
-           };
-           break;
-       case VDEF_MAXIMUM:
-       case VDEF_AVERAGE:
-       case VDEF_MINIMUM:
-       case VDEF_TOTAL:
-       case VDEF_FIRST:
-       case VDEF_LAST:
-           if (isnan(param)) {
-               gdes->vf.param = DNAN;
-               gdes->vf.val   = DNAN;
-               gdes->vf.when  = 0;
-           } else {
-               rrd_set_error("Function '%s' needs no parameter in VDEF '%s'\n"
-                   ,func
-                   ,gdes->vname
-                   );
-               return -1;
-           };
-           break;
+        case VDEF_PERCENT:
+            if (isnan(param)) { /* no parameter given */
+                rrd_set_error("Function '%s' needs parameter in VDEF '%s'\n"
+                    ,func
+                    ,gdes->vname
+                    );
+                return -1;
+            };
+            if (param>=0.0 && param<=100.0) {
+                gdes->vf.param = param;
+                gdes->vf.val   = DNAN;        /* undefined */
+                gdes->vf.when  = 0;        /* undefined */
+            } else {
+                rrd_set_error("Parameter '%f' out of range in VDEF '%s'\n"
+                    ,param
+                    ,gdes->vname
+                    );
+                return -1;
+            };
+            break;
+        case VDEF_MAXIMUM:
+        case VDEF_AVERAGE:
+        case VDEF_MINIMUM:
+        case VDEF_TOTAL:
+        case VDEF_FIRST:
+        case VDEF_LAST:
+        case VDEF_LSLSLOPE:
+        case VDEF_LSLINT:
+        case VDEF_LSLCORREL:
+            if (isnan(param)) {
+                gdes->vf.param = DNAN;
+                gdes->vf.val   = DNAN;
+                gdes->vf.when  = 0;
+            } else {
+                rrd_set_error("Function '%s' needs no parameter in VDEF '%s'\n"
+                    ,func
+                    ,gdes->vname
+                    );
+                return -1;
+            };
+            break;
     };
     return 0;
 }
@@ -3279,9 +3768,9 @@ vdef_calc(im,gdi)
 image_desc_t *im;
 int gdi;
 {
-    graph_desc_t       *src,*dst;
-    rrd_value_t                *data;
-    long               step,steps;
+    graph_desc_t        *src,*dst;
+    rrd_value_t                *data;
+    long                step,steps;
 
     dst = &im->gdes[gdi];
     src = &im->gdes[dst->vidx];
@@ -3297,124 +3786,166 @@ printf("DEBUG: start == %lu, end == %lu, %lu steps\n"
 #endif
 
     switch (dst->vf.op) {
-       case VDEF_PERCENT: {
-               rrd_value_t *   array;
-               int             field;
-
-
-               if ((array = malloc(steps*sizeof(double)))==NULL) {
-                   rrd_set_error("malloc VDEV_PERCENT");
-                   return -1;
-               }
-               for (step=0;step < steps; step++) {
-                   array[step]=data[step*src->ds_cnt];
-               }
-               qsort(array,step,sizeof(double),vdef_percent_compar);
-
-               field = (steps-1)*dst->vf.param/100;
-               dst->vf.val  = array[field];
-               dst->vf.when = 0;       /* no time component */
-               free(array);
+        case VDEF_PERCENT: {
+                rrd_value_t *        array;
+                int                field;
+
+
+                if ((array = malloc(steps*sizeof(double)))==NULL) {
+                    rrd_set_error("malloc VDEV_PERCENT");
+                    return -1;
+                }
+                for (step=0;step < steps; step++) {
+                    array[step]=data[step*src->ds_cnt];
+                }
+                qsort(array,step,sizeof(double),vdef_percent_compar);
+
+                field = (steps-1)*dst->vf.param/100;
+                dst->vf.val  = array[field];
+                dst->vf.when = 0;        /* no time component */
+                free(array);
 #if 0
 for(step=0;step<steps;step++)
 printf("DEBUG: %3li:%10.2f %c\n",step,array[step],step==field?'*':' ');
 #endif
-           }
-           break;
-       case VDEF_MAXIMUM:
-           step=0;
-           while (step != steps && isnan(data[step*src->ds_cnt])) step++;
-           if (step == steps) {
-               dst->vf.val  = DNAN;
-               dst->vf.when = 0;
-           } else {
-               dst->vf.val  = data[step*src->ds_cnt];
-               dst->vf.when = src->start + (step+1)*src->step;
-           }
-           while (step != steps) {
-               if (finite(data[step*src->ds_cnt])) {
-                   if (data[step*src->ds_cnt] > dst->vf.val) {
-                       dst->vf.val  = data[step*src->ds_cnt];
-                       dst->vf.when = src->start + (step+1)*src->step;
-                   }
-               }
-               step++;
-           }
-           break;
-       case VDEF_TOTAL:
-       case VDEF_AVERAGE: {
-           int cnt=0;
-           double sum=0.0;
-           for (step=0;step<steps;step++) {
-               if (finite(data[step*src->ds_cnt])) {
-                   sum += data[step*src->ds_cnt];
-                   cnt ++;
-               };
-           }
-           if (cnt) {
-               if (dst->vf.op == VDEF_TOTAL) {
-                   dst->vf.val  = sum*src->step;
-                   dst->vf.when = cnt*src->step;       /* not really "when" */
-               } else {
-                   dst->vf.val = sum/cnt;
-                   dst->vf.when = 0;   /* no time component */
-               };
-           } else {
-               dst->vf.val  = DNAN;
-               dst->vf.when = 0;
-           }
-           }
-           break;
-       case VDEF_MINIMUM:
-           step=0;
-           while (step != steps && isnan(data[step*src->ds_cnt])) step++;
-           if (step == steps) {
-               dst->vf.val  = DNAN;
-               dst->vf.when = 0;
-           } else {
-               dst->vf.val  = data[step*src->ds_cnt];
-               dst->vf.when = src->start + (step+1)*src->step;
-           }
-           while (step != steps) {
-               if (finite(data[step*src->ds_cnt])) {
-                   if (data[step*src->ds_cnt] < dst->vf.val) {
-                       dst->vf.val  = data[step*src->ds_cnt];
-                       dst->vf.when = src->start + (step+1)*src->step;
-                   }
-               }
-               step++;
-           }
-           break;
-       case VDEF_FIRST:
-           /* The time value returned here is one step before the
-            * actual time value.  This is the start of the first
-            * non-NaN interval.
-            */
-           step=0;
-           while (step != steps && isnan(data[step*src->ds_cnt])) step++;
-           if (step == steps) { /* all entries were NaN */
-               dst->vf.val  = DNAN;
-               dst->vf.when = 0;
-           } else {
-               dst->vf.val  = data[step*src->ds_cnt];
-               dst->vf.when = src->start + step*src->step;
-           }
-           break;
-       case VDEF_LAST:
-           /* The time value returned here is the
-            * actual time value.  This is the end of the last
-            * non-NaN interval.
-            */
-           step=steps-1;
-           while (step >= 0 && isnan(data[step*src->ds_cnt])) step--;
-           if (step < 0) { /* all entries were NaN */
-               dst->vf.val  = DNAN;
-               dst->vf.when = 0;
-           } else {
-               dst->vf.val  = data[step*src->ds_cnt];
-               dst->vf.when = src->start + (step+1)*src->step;
-           }
-           break;
+            }
+            break;
+        case VDEF_MAXIMUM:
+            step=0;
+            while (step != steps && isnan(data[step*src->ds_cnt])) step++;
+            if (step == steps) {
+                dst->vf.val  = DNAN;
+                dst->vf.when = 0;
+            } else {
+                dst->vf.val  = data[step*src->ds_cnt];
+                dst->vf.when = src->start + (step+1)*src->step;
+            }
+            while (step != steps) {
+                if (finite(data[step*src->ds_cnt])) {
+                    if (data[step*src->ds_cnt] > dst->vf.val) {
+                        dst->vf.val  = data[step*src->ds_cnt];
+                        dst->vf.when = src->start + (step+1)*src->step;
+                    }
+                }
+                step++;
+            }
+            break;
+        case VDEF_TOTAL:
+        case VDEF_AVERAGE: {
+            int cnt=0;
+            double sum=0.0;
+            for (step=0;step<steps;step++) {
+                if (finite(data[step*src->ds_cnt])) {
+                    sum += data[step*src->ds_cnt];
+                    cnt ++;
+                };
+            }
+            if (cnt) {
+                if (dst->vf.op == VDEF_TOTAL) {
+                    dst->vf.val  = sum*src->step;
+                    dst->vf.when = 0;        /* no time component */
+                } else {
+                    dst->vf.val = sum/cnt;
+                    dst->vf.when = 0;        /* no time component */
+                };
+            } else {
+                dst->vf.val  = DNAN;
+                dst->vf.when = 0;
+            }
+            }
+            break;
+        case VDEF_MINIMUM:
+            step=0;
+            while (step != steps && isnan(data[step*src->ds_cnt])) step++;
+            if (step == steps) {
+                dst->vf.val  = DNAN;
+                dst->vf.when = 0;
+            } else {
+                dst->vf.val  = data[step*src->ds_cnt];
+                dst->vf.when = src->start + (step+1)*src->step;
+            }
+            while (step != steps) {
+                if (finite(data[step*src->ds_cnt])) {
+                    if (data[step*src->ds_cnt] < dst->vf.val) {
+                        dst->vf.val  = data[step*src->ds_cnt];
+                        dst->vf.when = src->start + (step+1)*src->step;
+                    }
+                }
+                step++;
+            }
+            break;
+        case VDEF_FIRST:
+            /* The time value returned here is one step before the
+             * actual time value.  This is the start of the first
+             * non-NaN interval.
+             */
+            step=0;
+            while (step != steps && isnan(data[step*src->ds_cnt])) step++;
+            if (step == steps) { /* all entries were NaN */
+                dst->vf.val  = DNAN;
+                dst->vf.when = 0;
+            } else {
+                dst->vf.val  = data[step*src->ds_cnt];
+                dst->vf.when = src->start + step*src->step;
+            }
+            break;
+        case VDEF_LAST:
+            /* The time value returned here is the
+             * actual time value.  This is the end of the last
+             * non-NaN interval.
+             */
+            step=steps-1;
+            while (step >= 0 && isnan(data[step*src->ds_cnt])) step--;
+            if (step < 0) { /* all entries were NaN */
+                dst->vf.val  = DNAN;
+                dst->vf.when = 0;
+            } else {
+                dst->vf.val  = data[step*src->ds_cnt];
+                dst->vf.when = src->start + (step+1)*src->step;
+            }
+            break;
+        case VDEF_LSLSLOPE:
+        case VDEF_LSLINT:
+        case VDEF_LSLCORREL:{
+            /* Bestfit line by linear least squares method */ 
+
+            int cnt=0;
+            double SUMx, SUMy, SUMxy, SUMxx, SUMyy, slope, y_intercept, correl ;
+            SUMx = 0; SUMy = 0; SUMxy = 0; SUMxx = 0; SUMyy = 0;
+
+            for (step=0;step<steps;step++) {
+                if (finite(data[step*src->ds_cnt])) {
+                    cnt++;
+                    SUMx  += step;
+                    SUMxx += step * step;
+                    SUMxy += step * data[step*src->ds_cnt];
+                    SUMy  += data[step*src->ds_cnt];
+                    SUMyy  += data[step*src->ds_cnt]*data[step*src->ds_cnt];
+                };
+            }
+
+            slope = ( SUMx*SUMy - cnt*SUMxy ) / ( SUMx*SUMx - cnt*SUMxx );
+            y_intercept = ( SUMy - slope*SUMx ) / cnt;
+            correl = (SUMxy - (SUMx*SUMy)/cnt) / sqrt((SUMxx - (SUMx*SUMx)/cnt)*(SUMyy - (SUMy*SUMy)/cnt));
+
+            if (cnt) {
+                    if (dst->vf.op == VDEF_LSLSLOPE) {
+                        dst->vf.val  = slope;
+                        dst->vf.when = 0;
+                    } else if (dst->vf.op == VDEF_LSLINT)  {
+                        dst->vf.val = y_intercept;
+                        dst->vf.when = 0;
+                    } else if (dst->vf.op == VDEF_LSLCORREL)  {
+                        dst->vf.val = correl;
+                        dst->vf.when = 0;
+                    };
+                
+            } else {
+                dst->vf.val  = DNAN;
+                dst->vf.when = 0;
+            }
+        }
+        break;
     }
     return 0;
 }
index 10f583a7cc3fd717ad7d8b40a1466456202dcf54..e83b442aab6e0d6bb71ac1574ec858f5bd10359b 100644 (file)
@@ -5,23 +5,26 @@
 #include "rrd_rpncalc.h"
 #include "rrd_gfx.h"
 
-#define MAX_VNAME_LEN 29
-#define DEF_NAM_FMT "%29[-_A-Za-z0-9]"
+#define MAX_VNAME_LEN 255
+#define DEF_NAM_FMT "%255[-_A-Za-z0-9]"
 
-#define ALTYGRID       0x01    /* use alternative y grid algorithm */
-#define ALTAUTOSCALE   0x02    /* use alternative algorithm to find lower and upper bounds */
-#define ALTAUTOSCALE_MAX 0x04  /* use alternative algorithm to find upper bounds */
-#define NOLEGEND       0x08    /* use no legend */
-#define NOMINOR         0x20    /* Turn off minor gridlines */
-#define ONLY_GRAPH      0x24   /* use only graph */
-#define FORCE_RULES_LEGEND     0x40    /* force printing of HRULE and VRULE legend */
+#define ALTYGRID        0x01   /* use alternative y grid algorithm */
+#define ALTAUTOSCALE    0x02   /* use alternative algorithm to find lower and upper bounds */
+#define ALTAUTOSCALE_MIN 0x04  /* use alternative algorithm to find lower bounds */
+#define ALTAUTOSCALE_MAX 0x08  /* use alternative algorithm to find upper bounds */
+#define NOLEGEND        0x10   /* use no legend */
+#define NOMINOR          0x20    /* Turn off minor gridlines */
+#define ONLY_GRAPH       0x40   /* use only graph */
+#define FORCE_RULES_LEGEND 0x80        /* force printing of HRULE and VRULE legend */
 
+#define FORCE_UNITS 0x100        /* mask for all FORCE_UNITS_* flags */
+#define FORCE_UNITS_SI 0x100     /* force use of SI units in Y axis (no effect in linear graph, SI instead of E in log graph) */
 
 enum tmt_en {TMT_SECOND=0,TMT_MINUTE,TMT_HOUR,TMT_DAY,
             TMT_WEEK,TMT_MONTH,TMT_YEAR};
 
 enum grc_en {GRC_CANVAS=0,GRC_BACK,GRC_SHADEA,GRC_SHADEB,
-            GRC_GRID,GRC_MGRID,GRC_FONT,GRC_ARROW,GRC_AXIS,__GRC_END__};
+            GRC_GRID,GRC_MGRID,GRC_FONT,GRC_ARROW,GRC_AXIS,GRC_FRAME,__GRC_END__};
 
 #define MGRIDWIDTH 0.6
 #define GRIDWIDTH  0.4
@@ -35,13 +38,16 @@ enum gf_en {GF_PRINT=0,GF_GPRINT,GF_COMMENT,GF_HRULE,GF_VRULE,GF_LINE,
             GF_XPORT};
 
 enum vdef_op_en {
-                VDEF_MAXIMUM   /* like the MAX in (G)PRINT */
+                VDEF_MAXIMUM=0 /* like the MAX in (G)PRINT */
                ,VDEF_MINIMUM   /* like the MIN in (G)PRINT */
                ,VDEF_AVERAGE   /* like the AVERAGE in (G)PRINT */
                ,VDEF_PERCENT   /* Nth percentile */
                ,VDEF_TOTAL     /* average multiplied by time */
                ,VDEF_FIRST     /* first non-unknown value and time */
                ,VDEF_LAST      /* last  non-unknown value and time */
+               ,VDEF_LSLSLOPE  /* least squares line slope */
+               ,VDEF_LSLINT    /* least squares line y_intercept */
+               ,VDEF_LSLCORREL /* least squares line correlation coefficient */
                };
 enum text_prop_en { TEXT_PROP_DEFAULT=0,   /* default settings */
                    TEXT_PROP_TITLE,       /* properties for the title */
@@ -65,6 +71,7 @@ typedef struct vdef_t {
 
 typedef struct xlab_t {
     long         minsec;       /* minimum sec per pix */
+    long         length;       /* number of secs on the image */
     enum tmt_en  gridtm;       /* grid interval in what ?*/
     long         gridst;       /* how many whats per grid*/
     enum tmt_en  mgridtm;      /* label interval in what ?*/
@@ -112,6 +119,7 @@ typedef  struct graph_desc_t {
     gfx_color_t    col;        /* graph color */
     char  format[FMT_LEG_LEN+5]; /* format for PRINT AND GPRINT */
     char  legend[FMT_LEG_LEN+5]; /* legend*/
+    int            strftm;     /* should the VDEF legend be formated with strftime */
     double         leg_x,leg_y;  /* location of legend */   
     double         yrule;      /* value for y rule line and for VDEF */
     time_t         xrule;      /* time for x rule line and for VDEF */
@@ -125,7 +133,9 @@ typedef  struct graph_desc_t {
 
     /* description of data fetched for the graph element */
     time_t         start,end; /* timestaps for first and last data element */
+    time_t         start_orig,end_orig; /* timestaps for first and last data element */
     unsigned long  step;      /* time between samples */
+    unsigned long  step_orig;      /* time between samples */
     unsigned long  ds_cnt; /* how many data sources are there in the fetch */
     long           data_first; /* first pointer to this data */
     char           **ds_namv; /* name of datasources  in the fetch. */
@@ -146,13 +156,14 @@ typedef struct image_desc_t {
 #endif
     gfx_color_t    graph_col[__GRC_END__]; /* real colors for the graph */   
     text_prop_t    text_prop[TEXT_PROP_LAST]; /* text properties */
-    char           ylegend[200];   /* legend along the yaxis */
-    char           title[200];     /* title for graph */
+    char           ylegend[210];   /* legend along the yaxis */
+    char           title[210];     /* title for graph */
+    char           watermark[110];   /* watermark for graph */
     int            draw_x_grid;      /* no x-grid at all */
     int            draw_y_grid;      /* no x-grid at all */
     double         grid_dash_on, grid_dash_off;
     xlab_t         xlab_user;      /* user defined labeling for xaxis */
-    char           xlab_form[200]; /* format for the label on the xaxis */
+    char           xlab_form[210]; /* format for the label on the xaxis */
 
     double         ygridstep;      /* user defined step for y grid */
     int            ylabfact;       /* every how many y grid shall a label be written ? */
@@ -170,6 +181,7 @@ typedef struct image_desc_t {
     int            lazy;           /* only update the image if there is
                                      reasonable probablility that the
                                      existing one is out of date */
+    int                   slopemode;      /* connect the dots of the curve directly, not using a stair */
     int            logarithmic;    /* scale the yaxis logarithmic */
     
     /* status information */
@@ -180,9 +192,13 @@ typedef struct image_desc_t {
 #endif
     long           ximg,yimg;      /* total size of the image */
     double         magfact;        /* numerical magnitude*/
-    long         base;            /* 1000 or 1024 depending on what we graph */
+    long         base;             /* 1000 or 1024 depending on what we graph */
     char           symbol;         /* magnitude symbol for y-axis */
-    int            unitsexponent;    /* 10*exponent for units on y-asis */
+    float          viewfactor;     /* how should the numbers on the y-axis be scaled for viewing ? */
+    int            unitsexponent;  /* 10*exponent for units on y-asis */
+    int            unitslength;    /* width of the yaxis labels */
+    int            forceleftspace; /* do not kill the space to the left of the y-axis if there is no grid */
+
     int            extra_flags;    /* flags for boolean options */
     /* data elements */
 
@@ -228,15 +244,14 @@ int graph_paint(image_desc_t *, char ***);
 void pie_part(image_desc_t *, gfx_color_t, double, double, double, double, double);
 #endif
 int gdes_alloc(image_desc_t *);
-int scan_for_col(char *, int, char *);
+int scan_for_col(const char *const , int, char *const);
 int rrd_graph(int, char **, char ***, int *, int *, FILE *, double *, double *);
 void rrd_graph_init(image_desc_t *);
 void rrd_graph_options(int, char **, image_desc_t *);
 void rrd_graph_script(int, char **, image_desc_t *, int);
-int rrd_graph_check_vname(image_desc_t *, char *, char *);
 int rrd_graph_color(image_desc_t *, char *, char *, int);
 int bad_format(char *);
-int vdef_parse(struct graph_desc_t *,char *);
+int vdef_parse(struct graph_desc_t *,const char *const);
 int vdef_calc(image_desc_t *, int);
 int vdef_percent_compar(const void *,const void *);
 int graph_size_location(image_desc_t *, int
index 55185c93594d8c0662c57daa7202caa9ccfb8deb..20198edd97a57b623aa033559383f7e993443029 100644 (file)
@@ -1,42 +1,75 @@
 /****************************************************************************
- * RRDtool 1.2.x  Copyright Tobias Oetiker, 1997 - 2005
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  ****************************************************************************
  * rrd_graph_helper.c  commandline parser functions 
- *                     this code was probably writtenn by Alex van den Bogaerdt
+ *                     this code initially written by Alex van den Bogaerdt
  ****************************************************************************/
 
 #include "rrd_graph.h"
 
 #define dprintf if (gdp->debug) printf
 
+/* NOTE ON PARSING:
+ *
+ * we use the following:
+ * 
+ * i=0;  sscanf(&line[*eaten], "what to find%n", variables, &i)
+ *
+ * Usually you want to find a separator as well.  Example:
+ * i=0; sscanf(&line[*eaten], "%li:%n", &someint, &i)
+ *
+ * When the separator is not found, i is not set and thus remains zero.
+ * Another way would be to compare strlen() to i
+ *
+ * Why is this important?  Because 12345abc should not be matched as
+ * integer 12345 ...
+ */
+
+/* NOTE ON VNAMES:
+ *
+ * "if ((gdp->vidx=find_var(im, l))!=-1)" is not good enough, at least
+ * not by itself.
+ *
+ * A vname as a result of a VDEF is quite different from a vname
+ * resulting of a DEF or CDEF.
+ */
+
+/* NOTE ON VNAMES:
+ *
+ * A vname called "123" is not to be parsed as the number 123
+ */
+
+
 /* Define prototypes for the parsing methods.
   Inputs:
-   char *line         - pointer to base of input source
-   unsigned int eaten - index to next input character (INPUT/OUTPUT)
-   graph_desc_t *gdp  - pointer to a graph description
-   image_desc_t *im   - pointer to an image description
+   const char *const line    - a fixed pointer to a fixed string
+   unsigned int *const eaten - a fixed pointer to a changing index in that line
+   graph_desc_t *const gdp   - a fixed pointer to a changing graph description
+   image_desc_t *const im    - a fixed pointer to a changing image description
 */
 
-int rrd_parse_find_gf (char *, unsigned int *, graph_desc_t *);
-int rrd_parse_legend  (char *, unsigned int *, graph_desc_t *);
-int rrd_parse_color   (char *, graph_desc_t *);
-int rrd_parse_CF      (char *, unsigned int *, graph_desc_t *, enum cf_en *);
-int rrd_parse_print   (char *, unsigned int *, graph_desc_t *, image_desc_t *);
-int rrd_parse_shift   (char *, unsigned int *, graph_desc_t *, image_desc_t *);
-int rrd_parse_xport   (char *, unsigned int *, graph_desc_t *, image_desc_t *);
-int rrd_parse_PVHLAST (char *, unsigned int *, graph_desc_t *, image_desc_t *);
-int rrd_parse_vname   (char *, unsigned int *, graph_desc_t *, image_desc_t *);
-int rrd_parse_def     (char *, unsigned int *, graph_desc_t *, image_desc_t *);
-int rrd_parse_vdef    (char *, unsigned int *, graph_desc_t *, image_desc_t *);
-int rrd_parse_cdef    (char *, unsigned int *, graph_desc_t *, image_desc_t *);
+int rrd_parse_find_gf (const char * const, unsigned int *const, graph_desc_t *const);
+int rrd_parse_legend  (const char * const, unsigned int *const, graph_desc_t *const);
+int rrd_parse_color   (const char * const, graph_desc_t *const);
+int rrd_parse_CF      (const char * const, unsigned int *const, graph_desc_t *const, enum cf_en *const);
+int rrd_parse_print   (const char * const, unsigned int *const, graph_desc_t *const, image_desc_t *const);
+int rrd_parse_shift   (const char * const, unsigned int *const, graph_desc_t *const, image_desc_t *const);
+int rrd_parse_xport   (const char * const, unsigned int *const, graph_desc_t *const, image_desc_t *const);
+int rrd_parse_PVHLAST (const char * const, unsigned int *const, graph_desc_t *const, image_desc_t *const);
+int rrd_parse_make_vname   (const char * const, unsigned int *const, graph_desc_t *const, image_desc_t *const);
+int rrd_parse_find_vname   (const char * const, unsigned int *const, graph_desc_t *const, image_desc_t *const);
+int rrd_parse_def     (const char * const, unsigned int *const, graph_desc_t *const, image_desc_t *const);
+int rrd_parse_vdef    (const char * const, unsigned int *const, graph_desc_t *const, image_desc_t *const);
+int rrd_parse_cdef    (const char * const, unsigned int *const, graph_desc_t *const, image_desc_t *const);
 
 
 
 int
-rrd_parse_find_gf(char *line, unsigned int *eaten, graph_desc_t *gdp) {
-    char funcname[11],c1=0,c2=0;
+rrd_parse_find_gf(const char *const line, unsigned int *const eaten, graph_desc_t *const gdp) {
+    char funcname[11],c1=0;
     int i=0;
 
+    /* start an argument with DEBUG to be able to see how it is parsed */
     sscanf(&line[*eaten], "DEBUG%n", &i);
     if (i) {
        gdp->debug=1;
@@ -44,73 +77,133 @@ rrd_parse_find_gf(char *line, unsigned int *eaten, graph_desc_t *gdp) {
        i=0;
        dprintf("Scanning line '%s'\n",&line[*eaten]);
     }
-    sscanf(&line[*eaten], "%10[A-Z]%n%c%c", funcname, &i, &c1, &c2);
+    i=0;c1='\0';
+    sscanf(&line[*eaten], "%10[A-Z]%n%c", funcname, &i, &c1);
     if (!i) {
        rrd_set_error("Could not make sense out of '%s'",line);
        return 1;
     }
+    (*eaten)+=i;
     if ((int)(gdp->gf=gf_conv(funcname)) == -1) {
        rrd_set_error("'%s' is not a valid function name", funcname);
        return 1;
-    }
-    if (gdp->gf == GF_LINE) {
-       if (c1 < '1' || c1 > '3' || c2 != ':') {
-           rrd_set_error("Malformed LINE command: %s",line);
-           return 1;
-       }
-       gdp->linewidth=c1-'0';
-       i++;
     } else {
-       if (c1 != ':') {
-           rrd_set_error("Malformed %s command: %s",funcname,line);
+       dprintf("- found function name '%s'\n",funcname);
+    }
+
+    if (c1 == '\0') {
+       rrd_set_error("Function %s needs parameters.  Line: %s\n",funcname,line);
+       return 1;
+    }
+    if (c1 == ':') (*eaten)++;
+
+    /* Some commands have a parameter before the colon
+     * (currently only LINE)
+     */
+    switch (gdp->gf) {
+       case GF_LINE:
+           if (c1 == ':') {
+               gdp->linewidth=1;
+               dprintf("- - using default width of 1\n");
+           } else {
+               i=0;sscanf(&line[*eaten],"%lf:%n",&gdp->linewidth,&i);
+               if (!i) {
+                   rrd_set_error("Cannot parse line width '%s' in line '%s'\n",&line[*eaten],line);
+                   return 1;
+               } else {
+                   dprintf("- - scanned width %f\n",gdp->linewidth);
+                   if (isnan(gdp->linewidth)) {
+                       rrd_set_error("LINE width '%s' is not a number in line '%s'\n",&line[*eaten],line);
+                       return 1;
+                   }
+                   if (isinf(gdp->linewidth)) {
+                       rrd_set_error("LINE width '%s' is out of range in line '%s'\n",&line[*eaten],line);
+                       return 1;
+                   }
+                   if (gdp->linewidth<0) {
+                       rrd_set_error("LINE width '%s' is less than 0 in line '%s'\n",&line[*eaten],line);
+                       return 1;
+                   }
+               }
+               (*eaten)+=i;
+           }
+           break;
+       default:
+           if (c1 == ':') break;
+           rrd_set_error("Malformed '%s' command in line '%s'\n",&line[*eaten],line);
            return 1;
-       }
     }
-    *eaten+=++i;
+    if (line[*eaten] == '\0') {
+       rrd_set_error("Expected some arguments after '%s'\n",line);
+       return 1;
+    }
     return 0;
 }
 
 int
-rrd_parse_legend(char *line, unsigned int *eaten, graph_desc_t *gdp) {
+rrd_parse_legend(const char *const line, unsigned int *const eaten, graph_desc_t *const gdp) {
     int i;
 
-    dprintf("- examining '%s'\n",&line[*eaten]);
+    if (line[*eaten]=='\0' || line[*eaten]==':') {
+       dprintf("- no (or: empty) legend found\n");
+       return 0;
+    }
 
     i=scan_for_col(&line[*eaten],FMT_LEG_LEN,gdp->legend);
 
-    *eaten += i;
+    (*eaten)+=i;
+
     if (line[*eaten]!='\0' && line[*eaten]!=':') {
        rrd_set_error("Legend too long");
        return 1;
     } else {
-       dprintf("- found legend '%s'\n", gdp->legend);
        return 0;
     }
 }
 
 int
-rrd_parse_color(char *string, graph_desc_t *gdp) {
-    unsigned int r=0,g=0,b=0,a=0;
-    int i1=0,i2=0,i3=0;
-
-    if (string[0] != '#') return 1;
-    sscanf(string, "#%02x%02x%02x%n%02x%n%*s%n",
-                               &r,&g,&b,&i1,&a,&i2,&i3);
+rrd_parse_color(const char *const string, graph_desc_t *const gdp) {
+    unsigned int r=0,g=0,b=0,a=0,i;
+
+    /* matches the following formats:
+    ** RGB
+    ** RGBA
+    ** RRGGBB
+    ** RRGGBBAA
+    */
 
-    if (i3) return 1; /* garbage after color */
-    if (!i2) a=0xFF;
-    if (!i1) return 1; /* no color after '#' */
+    i=0;
+    while (string[i] && isxdigit((unsigned int)string[i])) i++;
+    if (string[i] != '\0') return 1; /* garbage follows hexdigits */
+    switch (i) {
+       case 3:
+       case 4:
+           sscanf(string, "%1x%1x%1x%1x",&r,&g,&b,&a);
+           r *= 0x11;
+           g *= 0x11;
+           b *= 0x11;
+           a *= 0x11;
+           if (i==3) a=0xFF;
+           break;
+       case 6:
+       case 8:
+           sscanf(string, "%02x%02x%02x%02x",&r,&g,&b,&a);
+           if (i==6) a=0xFF;
+           break;
+       default:
+           return 1;   /* wrong number of digits */
+    }
     gdp->col = r<<24|g<<16|b<<8|a;
     return 0;
 }
 
 int
-rrd_parse_CF(char *line, unsigned int *eaten, graph_desc_t *gdp, enum cf_en *cf) {
+rrd_parse_CF(const char *const line, unsigned int *const eaten, graph_desc_t *const gdp, enum cf_en *cf) {
     char               symname[CF_NAM_SIZE];
     int                        i=0;
 
     sscanf(&line[*eaten], CF_NAM_FMT "%n", symname,&i);
-    if ((!i)||((line[*eaten+i]!='\0')&&(line[*eaten+i]!=':'))) {
+    if ((!i)||((line[(*eaten)+i]!='\0')&&(line[(*eaten)+i]!=':'))) {
        rrd_set_error("Cannot parse CF in '%s'",line);
        return 1;
     }
@@ -126,28 +219,51 @@ rrd_parse_CF(char *line, unsigned int *eaten, graph_desc_t *gdp, enum cf_en *cf)
     return 0;
 }
 
-/* Parsing old-style xPRINT and new-style xPRINT */
+/* Try to match next token as a vname.
+ *
+ * Returns:
+ * -1     an error occured and the error string is set
+ * other  the vname index number
+ *
+ * *eaten is incremented only when a vname is found.
+ */
 int
-rrd_parse_print(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t *im) {
-    /* vname:CF:format in case of DEF-based vname
-    ** vname:CF:format in case of CDEF-based vname
-    ** vname:format in case of VDEF-based vname
-    */
+rrd_parse_find_vname(const char *const line, unsigned int *const eaten, graph_desc_t *const gdp, image_desc_t *const im) {
     char tmpstr[MAX_VNAME_LEN+1];
-    int i=0;
+    int i;
+    long vidx;
 
-    sscanf(&line[*eaten], DEF_NAM_FMT ":%n", tmpstr,&i);
+    i=0;sscanf(&line[*eaten], DEF_NAM_FMT "%n", tmpstr,&i);
     if (!i) {
        rrd_set_error("Could not parse line '%s'",line);
-       return 1;
+       return -1;
     }
-    (*eaten)+=i;
-    dprintf("- Found candidate vname '%s'\n",tmpstr);
+    if (line[*eaten+i]!=':' && line[*eaten+i]!='\0') {
+       rrd_set_error("Could not parse line '%s'",line);
+       return -1;
+    }
+    dprintf("- Considering '%s'\n",tmpstr);
 
-    if ((gdp->vidx=find_var(im,tmpstr))<0) {
+    if ((vidx=find_var(im,tmpstr))<0) {
+       dprintf("- Not a vname\n");
        rrd_set_error("Not a valid vname: %s in line %s",tmpstr,line);
-       return 1;
+       return -1;
     }
+    dprintf("- Found vname '%s' vidx '%li'\n",tmpstr,gdp->vidx);
+    if (line[*eaten+i]==':') i++;
+    (*eaten)+=i;
+    return vidx;
+}
+
+/* Parsing old-style xPRINT and new-style xPRINT */
+int
+rrd_parse_print(const char *const line, unsigned int *const eaten, graph_desc_t *const gdp, image_desc_t *const im) {
+    /* vname:CF:format in case of DEF-based vname
+    ** vname:CF:format in case of CDEF-based vname
+    ** vname:format[:strftime] in case of VDEF-based vname
+    */
+    if ((gdp->vidx=rrd_parse_find_vname(line,eaten,gdp,im))<0) return 1;
     switch (im->gdes[gdp->vidx].gf) {
        case GF_DEF:
        case GF_CDEF:
@@ -158,95 +274,98 @@ rrd_parse_print(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t
            dprintf("- vname is of type VDEF\n");
            break;
        default:
-           rrd_set_error("Encountered unknown type variable '%s'",tmpstr);
+           rrd_set_error("Encountered unknown type variable '%s'",im->gdes[gdp->vidx].vname);
            return 1;
     }
 
     if (rrd_parse_legend(line,eaten,gdp)) return 1;
-    /* for *PRINT the legend itself gets renderd later. We only
+    /* for *PRINT the legend itself gets rendered later. We only
        get the format at this juncture */
     strcpy(gdp->format,gdp->legend);
     gdp->legend[0]='\0';       
+    /* this is a very crud test, parsing :style flags should be in a function */
+    if (im->gdes[gdp->vidx].gf == GF_VDEF && strcmp(line+(*eaten),":strftime")==0){
+       gdp->strftm = 1;
+        (*eaten)+=strlen(":strftime");
+    }
     return 0;
 }
 
+/* SHIFT:_def_or_cdef:_vdef_or_number_
+ */
 int
-rrd_parse_shift(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t *im) {
-       char    *l = strdup(line + *eaten), *p;
-       int     rc = 1;
-
-       p = strchr(l, ':');
-       if (p == NULL) {
-               rrd_set_error("Invalid SHIFT syntax");
-               goto out;
-       }
-       *p++ = '\0';
-       
-       if ((gdp->vidx=find_var(im,l))<0) {
-               rrd_set_error("Not a valid vname: %s in line %s",l,line);
-               goto out;
+rrd_parse_shift(const char *const line, unsigned int *const eaten, graph_desc_t *const gdp, image_desc_t *const im) {
+    int i;
+
+    if ((gdp->vidx=rrd_parse_find_vname(line,eaten,gdp,im))<0) return 1;
+
+    switch (im->gdes[gdp->vidx].gf) {
+       case GF_DEF:
+       case GF_CDEF:
+           dprintf("- vname is of type DEF or CDEF, OK\n");
+           break;
+       case GF_VDEF:
+           rrd_set_error("Cannot shift a VDEF: '%s' in line '%s'\n",im->gdes[gdp->vidx].vname,line);
+           return 1;
+       default:
+           rrd_set_error("Encountered unknown type variable '%s' in line '%s'",im->gdes[gdp->vidx].vname,line);
+           return 1;
+    }
+
+    if ((gdp->shidx=rrd_parse_find_vname(line,eaten,gdp,im))>=0) {
+       switch (im->gdes[gdp->shidx].gf) {
+           case GF_DEF:
+           case GF_CDEF:
+               rrd_set_error("Offset cannot be a (C)DEF: '%s' in line '%s'\n",im->gdes[gdp->shidx].vname,line);
+               return 1;
+           case GF_VDEF:
+               dprintf("- vname is of type VDEF, OK\n");
+               break;
+           default:
+               rrd_set_error("Encountered unknown type variable '%s' in line '%s'",im->gdes[gdp->vidx].vname,line);
+               return 1;
        }
-       
-        /* constant will parse; otherwise, must be VDEF reference */
-       if (sscanf(p, "%ld", &gdp->shval) != 1) {
-               graph_desc_t    *vdp;
-               
-               if ((gdp->shidx=find_var(im, p))<0) {
-                       rrd_set_error("invalid offset vname: %s", p);
-                       goto out;
-               }
-               
-               vdp = &im->gdes[gdp->shidx];
-               if (vdp->gf != GF_VDEF) {
-                       rrd_set_error("offset must specify value or VDEF");
-                       goto out;
-               }
-       } else {
-               gdp->shidx = -1;
+    } else {
+       rrd_clear_error();
+       i=0; sscanf(&line[*eaten],"%li%n",&gdp->shval,&i);
+       if (i!=(int)strlen(&line[*eaten])) {
+           rrd_set_error("Not a valid offset: %s in line %s",&line[*eaten],line);
+           return 1;
        }
-       
-       *eaten = strlen(line);
-       rc = 0;
-
- out:
-       free(l);
-       return rc;
+       (*eaten)+=i;
+       dprintf("- offset is number %li\n",gdp->shval);
+       gdp->shidx = -1;
+    }
+    return 0;
 }
 
+/* XPORT:_def_or_cdef[:legend]
+ */
 int
-rrd_parse_xport(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t *im) {
-       char    *l = strdup(line + *eaten), *p;
-       int     rc = 1;
-
-       p = strchr(l, ':');
-       if (p != NULL)
-               *p++ = '\0';
-       else
-               p = "";
-       
-       if ((gdp->vidx=find_var(im, l))==-1){
-               rrd_set_error("unknown variable '%s'",l);
-               goto out;
-       }
-       
-       if (strlen(p) >= FMT_LEG_LEN)
-               *(p + FMT_LEG_LEN) = '\0';
-       
-       strcpy(gdp->legend, p);
-       *eaten = strlen(line);
-       rc = 0;
-       
- out:
-       free(l);
-       return rc;
+rrd_parse_xport(const char *const line, unsigned int *const eaten, graph_desc_t *const gdp, image_desc_t *const im) {
+    if ((gdp->vidx=rrd_parse_find_vname(line,eaten,gdp,im))<0) return 1;
+
+    switch (im->gdes[gdp->vidx].gf) {
+       case GF_DEF:
+       case GF_CDEF:
+           dprintf("- vname is of type DEF or CDEF, OK\n");
+           break;
+       case GF_VDEF:
+           rrd_set_error("Cannot xport a VDEF: '%s' in line '%s'\n",im->gdes[gdp->vidx].vname,line);
+           return 1;
+       default:
+           rrd_set_error("Encountered unknown type variable '%s' in line '%s'",im->gdes[gdp->vidx].vname,line);
+           return 1;
+    }
+    dprintf("- looking for legend in '%s'\n",&line[*eaten]);
+    if (rrd_parse_legend(line,eaten,gdp)) return 1;
+    return 0;
 }
 
 /* Parsing of PART, VRULE, HRULE, LINE, AREA, STACK and TICK
-** is done in one function.  Stacking STACK is silently ignored
-** as it is redundant.  Stacking PART, VRULE, HRULE or TICK is
-** not allowed.  The check for color doesn't need to be so strict
-** anymore, the user can specify the color '#00000000' and
-** effectively circumvent this check, so why bother.
+** is done in one function.
+**
+** Stacking PART, VRULE, HRULE or TICK is not allowed.
 **
 ** If a number (which is valid to enter) is more than a
 ** certain amount of characters, it is caught as an error.
@@ -254,13 +373,32 @@ rrd_parse_xport(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t
 ** with more than MAX_VNAME_LEN significant digits.
 */
 int
-rrd_parse_PVHLAST(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t *im) {
-    int i,j;
+rrd_parse_PVHLAST(const char *const line, unsigned int *const eaten, graph_desc_t *const gdp, image_desc_t *const im) {
+    int i,j,k;
     int colorfound=0;
     char tmpstr[MAX_VNAME_LEN + 10];   /* vname#RRGGBBAA\0 */
+    static int spacecnt = 0;
+
+    if (spacecnt == 0) {        
+       float one_space = gfx_get_text_width(im->canvas, 0,
+                               im->text_prop[TEXT_PROP_LEGEND].font,
+                               im->text_prop[TEXT_PROP_LEGEND].size,
+                               im->tabwidth,"    ", 0) / 4.0;
+       float target_space = gfx_get_text_width(im->canvas, 0,
+                               im->text_prop[TEXT_PROP_LEGEND].font,
+                               im->text_prop[TEXT_PROP_LEGEND].size,
+                               im->tabwidth,"oo", 0);
+       spacecnt =  target_space / one_space;   
+        dprintf("- spacecnt: %i onespace: %f targspace: %f\n",spacecnt,one_space,target_space);
+    }
+
 
     dprintf("- parsing '%s'\n",&line[*eaten]);
-    dprintf("- from line '%s'\n",line);
+
+    /* have simpler code in the drawing section */
+    if ( gdp->gf == GF_STACK ){
+           gdp->stack=1;
+    }
 
     i=scan_for_col(&line[*eaten],MAX_VNAME_LEN+9,tmpstr);
     if (line[*eaten+i]!='\0' && line[*eaten+i]!=':') {
@@ -270,81 +408,155 @@ rrd_parse_PVHLAST(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc
 
     j=i; while (j>0 && tmpstr[j]!='#') j--;
 
-    if (tmpstr[j]=='#') {
+    if (j) {
+       tmpstr[j]='\0';
+    }
+    /* We now have:
+     * tmpstr[0]    containing vname
+     * tmpstr[j]    if j!=0 then containing color
+     * i            size of vname + color
+     * j            if j!=0 then size of vname
+     */
+
+    /* Number or vname ?
+     * If it is an existing vname, that's OK, provided that it is a
+     * valid type (need time for VRULE, not a float)
+     * Else see if it parses as a number.
+     */
+    dprintf("- examining string '%s'\n",tmpstr);
+    if ((gdp->vidx=find_var(im,tmpstr))>=0) {
+       dprintf("- found vname: '%s' vidx %li\n",tmpstr,gdp->vidx);
+       switch (gdp->gf) {
+#ifdef WITH_PIECHART
+           case GF_PART:
+#endif
+           case GF_VRULE:
+           case GF_HRULE:
+               if (im->gdes[gdp->vidx].gf != GF_VDEF) {
+                   rrd_set_error("Using vname %s of wrong type in line %s\n",im->gdes[gdp->gf].vname,line);
+                   return 1;
+               }
+               break;
+           default:;
+       }
+    } else {
+       dprintf("- it is not an existing vname\n");
+       switch (gdp->gf) {
+           case GF_VRULE:
+               k=0;sscanf(tmpstr,"%li%n",&gdp->xrule,&k);
+               if (((j!=0)&&(k==j))||((j==0)&&(k==i))) {
+                   dprintf("- found time: %li\n",gdp->xrule);
+               } else {
+                   dprintf("- is is not a valid number: %li\n",gdp->xrule);
+                   rrd_set_error("parameter '%s' does not represent time in line %s\n",tmpstr,line);
+                   return 1;
+               }
+           default:
+               k=0;sscanf(tmpstr,"%lf%n",&gdp->yrule,&k);
+               if (((j!=0)&&(k==j))||((j==0)&&(k==i))) {
+                   dprintf("- found number: %f\n",gdp->yrule);
+               } else {
+                   dprintf("- is is not a valid number: %li\n",gdp->xrule);
+                   rrd_set_error("parameter '%s' does not represent a number in line %s\n",tmpstr,line);
+                   return 1;
+               }
+       }
+    }
+
+    if (j) {
+       j++;
+       dprintf("- examining color '%s'\n",&tmpstr[j]);
        if (rrd_parse_color(&tmpstr[j],gdp)) {
-           rrd_set_error("Could not parse color in '%s'",tmpstr[j]);
+           rrd_set_error("Could not parse color in '%s'",&tmpstr[j]);
            return 1;
        }
-       tmpstr[j]='\0';
        dprintf("- parsed color 0x%08x\n",(unsigned int)gdp->col);
        colorfound=1;
+    } else {
+       dprintf("- no color present in '%s'\n",tmpstr);
     }
 
-    dprintf("- examining '%s'\n",tmpstr);
-    j=0;
-    if (gdp->gf == GF_VRULE) {
-       sscanf(tmpstr,"%li%n",&gdp->xrule,&j);
-       if (j) dprintf("- found time: %li\n",gdp->xrule);
-    } else {
-       sscanf(tmpstr,"%lf%n",&gdp->yrule,&j);
-       if (j) dprintf("- found number: %f\n",gdp->yrule);
+    (*eaten) += i; /* after vname#color */
+    if (line[*eaten]!='\0') {
+       (*eaten)++;     /* after colon */
     }
-    if (!j) {
-       if ((gdp->vidx=find_var(im,tmpstr))<0) {
-           rrd_set_error("Not a valid vname: %s in line %s",tmpstr,line);
-           return 1;
+
+    if (gdp->gf == GF_TICK) {
+       dprintf("- parsing '%s'\n",&line[*eaten]);
+       dprintf("- looking for optional TICK number\n");
+       j=0;
+       sscanf(&line[*eaten],"%lf%n",&gdp->yrule,&j);
+       if (j) {
+           if (line[*eaten+j]!='\0' && line[*eaten+j]!=':') {
+               rrd_set_error("Cannot parse TICK fraction '%s'",line);
+               return 1;
+           }
+           dprintf("- found number %f\n",gdp->yrule);
+           if (gdp->yrule > 1.0 || gdp->yrule < -1.0) {
+               rrd_set_error("Tick factor should be <= 1.0");
+               return 1;
+           }
+           (*eaten)+=j;
+       } else {
+            dprintf("- not found, defaulting to 0.1\n");
+            gdp->yrule=0.1;
        }
-       dprintf("- found vname: '%s' vidx %li\n",tmpstr,gdp->vidx);
-    }
-    /* "*eaten" is still pointing to the original location,
-    ** "*eaten +i" is pointing to the character after the color
-    ** or to the terminating '\0' in which case we're finished.
-    */
-    if (line[*eaten+i]=='\0') {
-       *eaten+=i;
-       return 0;
+       if (line[*eaten] == '\0') {
+           dprintf("- done parsing line\n");
+           return 0;
+       } else { if (line[*eaten] == ':') {
+                   (*eaten)++;    
+                } else {
+                    rrd_set_error("Can't make sense of that TICK line");
+                  return 1;
+                 }
+        }
     }
-    *eaten+=++i;
 
-    /* If a color is specified and the only remaining part is
-    ** ":STACK" then it is assumed to be the legend.  An empty
-    ** legend can be specified as expected.  This means the
-    ** following can be done:  LINE1:x#FF0000FF::STACK
+    dprintf("- parsing '%s'\n",&line[*eaten]);
+
+    /* Legend is next.  A legend without a color is an error.
+    ** Stacking an item without having a legend is OK however
+    ** then an empty legend should be specified.
+    **   LINE:val#color:STACK  means legend is string "STACK"
+    **   LINE:val#color::STACK means no legend, and do STACK
+    **   LINE:val:STACK                is an error (legend but no color)
+    **   LINE:val::STACK       means no legend, and do STACK
     */
-    if (colorfound) { /* no legend if no color */
-       if (gdp->gf == GF_TICK) {
-           dprintf("- looking for optional number\n");
-           sscanf(&line[*eaten],"%lf%n",&gdp->yrule,&j);
-           if (j) {
-               dprintf("- found number %f\n",gdp->yrule);
-               (*eaten)+=j;
-               if (gdp->yrule > 1.0 || gdp->yrule < -1.0) {
-                   rrd_set_error("Tick factor should be <= 1.0");
-                   return 1;
-               }
-               if (line[*eaten] == ':')
-                   (*eaten)++;
-           } else {
-               dprintf("- not found, defaulting to 0.1\n");
-               gdp->yrule=0.1;
-               return 0;
+    if (colorfound) {
+       int err=0;
+        char *linecp = strdup(line);
+       dprintf("- looking for optional legend\n");
+       
+       dprintf("- examining '%s'\n",&line[*eaten]);
+       if (linecp[*eaten] != '\0' && linecp[*eaten] != ':') {
+           int spi;            
+           /* If the legend is not empty, it has to be prefixed with spacecnt ' ' characters. This then gets
+            * replaced by the color box later on. */
+           for (spi=0;spi<spacecnt && (*eaten) > 1;spi++){
+              linecp[--(*eaten)]=' ';
            }
        }
-       dprintf("- looking for optional legend\n");
-       dprintf("- in '%s'\n",&line[*eaten]);
-       /* the legend for a graph item must start with "m " the first
-           m will then be over drawn with a color box. Since there
-           is ample space I overwrite the first few characters of the line
-          with the material that I want to see in the legend */
-       if (line[*eaten] != '\0' && line[*eaten] != ':'){
-               *eaten = *eaten - 2;
-               line[*eaten] = 'm';
-               line[*eaten+1] = ' ';
-       }       
-       if (rrd_parse_legend(line, eaten, gdp)) return 1;
-    }
-
-    /* PART, HRULE, VRULE and TICK cannot be stacked.  We're finished */
+
+       if (rrd_parse_legend(linecp, eaten, gdp)) err=1;
+       free(linecp);
+       if (err) return 1;
+
+       dprintf("- found legend '%s'\n", &gdp->legend[2]);
+    } else {
+       dprintf("- skipping empty legend\n");
+       if (line[*eaten] != '\0' && line[*eaten] != ':') {
+           rrd_set_error("Legend set but no color: %s",&line[*eaten]);
+           return 1;
+       }
+    }
+    if (line[*eaten]=='\0') {
+       dprintf("- done parsing line\n");
+       return 0;
+    }
+    (*eaten)++;        /* after colon */
+
+    /* PART, HRULE, VRULE and TICK cannot be stacked. */
     if (   (gdp->gf == GF_HRULE)
        || (gdp->gf == GF_VRULE)
 #ifdef WITH_PIECHART
@@ -353,28 +565,36 @@ rrd_parse_PVHLAST(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc
        || (gdp->gf == GF_TICK)
        ) return 0;
 
+    dprintf("- parsing '%s'\n",&line[*eaten]);
     if (line[*eaten]!='\0') {
        dprintf("- still more, should be STACK\n");
-       (*eaten)++;
        j=scan_for_col(&line[*eaten],5,tmpstr);
-       if (line[*eaten+j]!='\0') {
+       if (line[*eaten+j]!='\0' && line[*eaten+j]!=':') {
+           /* not 5 chars */
            rrd_set_error("Garbage found where STACK expected");
            return 1;
        }
        if (!strcmp("STACK",tmpstr)) {
            dprintf("- found STACK\n");
            gdp->stack=1;
-           (*eaten)+=5;
+           (*eaten)+=j;
        } else {
            rrd_set_error("Garbage found where STACK expected");
            return 1;
        }
     }
+    if (line[*eaten]=='\0') {
+       dprintf("- done parsing line\n");
+       return 0;
+    }
+    (*eaten)++;
+    dprintf("- parsing '%s'\n",&line[*eaten]);
+
     return 0;
 }
 
 int
-rrd_parse_vname(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t *im) {
+rrd_parse_make_vname(const char *const line, unsigned int *const eaten, graph_desc_t *const gdp, image_desc_t *const im) {
     char tmpstr[MAX_VNAME_LEN + 10];
     int i=0;
 
@@ -396,7 +616,7 @@ rrd_parse_vname(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t
 }
 
 int
-rrd_parse_def(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t *im) {
+rrd_parse_def(const char *const line, unsigned int *const eaten, graph_desc_t *const gdp, image_desc_t *const im) {
     int                        i=0;
     char               command[7]; /* step, start, end, reduce */
     char               tmpstr[256];
@@ -412,8 +632,8 @@ rrd_parse_def(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t *
     dprintf("- parsing '%s'\n",&line[*eaten]);
     dprintf("- from line '%s'\n",line);
 
-    if (rrd_parse_vname(line,eaten,gdp,im)) return 1;
-    i=scan_for_col(&line[*eaten],254,gdp->rrd);
+    if (rrd_parse_make_vname(line,eaten,gdp,im)) return 1;
+    i=scan_for_col(&line[*eaten],sizeof(gdp->rrd)-1,gdp->rrd);
     if (line[*eaten+i]!=':') {
        rrd_set_error("Problems reading database name");
        return 1;
@@ -452,6 +672,7 @@ rrd_parse_def(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t *
        } else if (!strcmp("step",command)) {
            i=0;
            sscanf(&line[*eaten],"%lu%n",&gdp->step,&i);
+           gdp->step_orig = gdp->step;
            (*eaten)+=i;
            dprintf("- using step %lu\n",gdp->step);
        } else if (!strcmp("start",command)) {
@@ -501,6 +722,8 @@ rrd_parse_def(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t *
 
     gdp->start = start_tmp;
     gdp->end = end_tmp;
+    gdp->start_orig = start_tmp;
+    gdp->end_orig = end_tmp;
 
     dprintf("- start time %lu\n",gdp->start);
     dprintf("- end   time %lu\n",gdp->end);
@@ -509,12 +732,12 @@ rrd_parse_def(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t *
 }
 
 int
-rrd_parse_vdef(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t *im) {
+rrd_parse_vdef(const char *const line, unsigned int *const eaten, graph_desc_t *const gdp, image_desc_t *const im) {
     char tmpstr[MAX_VNAME_LEN+1];      /* vname\0 */
     int i=0;
 
     dprintf("- parsing '%s'\n",&line[*eaten]);
-    if (rrd_parse_vname(line,eaten,gdp,im)) return 1;
+    if (rrd_parse_make_vname(line,eaten,gdp,im)) return 1;
 
     sscanf(&line[*eaten], DEF_NAM_FMT ",%n", tmpstr,&i);
     if (!i) {
@@ -543,9 +766,9 @@ rrd_parse_vdef(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t
 }
 
 int
-rrd_parse_cdef(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t *im) {
+rrd_parse_cdef(const char *const line, unsigned int *const eaten, graph_desc_t *const gdp, image_desc_t *const im) {
     dprintf("- parsing '%s'\n",&line[*eaten]);
-    if (rrd_parse_vname(line,eaten,gdp,im)) return 1;
+    if (rrd_parse_make_vname(line,eaten,gdp,im)) return 1;
     if ((gdp->rpnp = rpn_parse(
        (void *)im,
        &line[*eaten],
@@ -560,8 +783,11 @@ rrd_parse_cdef(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t
 }
 
 void
-rrd_graph_script(int argc, char *argv[], image_desc_t *im, int optno) {
+rrd_graph_script(int argc, char *argv[], image_desc_t *const im, int optno) {
     int i;
+    /* save state for STACK backward compat function */
+    enum gf_en     last_gf=GF_PRINT;
+    float          last_linewidth=0.0;
 
     for (i=optind+optno;i<argc;i++) {
        graph_desc_t *gdp;
@@ -574,7 +800,7 @@ rrd_graph_script(int argc, char *argv[], image_desc_t *im, int optno) {
 #endif
 
        if (rrd_parse_find_gf(argv[i],&eaten,gdp)) return;
-
+        
        switch (gdp->gf) {
            case GF_SHIFT:      /* vname:value */
                if (rrd_parse_shift(argv[i],&eaten,gdp,im)) return;
@@ -583,6 +809,7 @@ rrd_graph_script(int argc, char *argv[], image_desc_t *im, int optno) {
                if (rrd_parse_xport(argv[i],&eaten,gdp,im)) return;
                break;
            case GF_PRINT:      /* vname:CF:format -or- vname:format */
+               im->prt_c++;            
            case GF_GPRINT:     /* vname:CF:format -or- vname:format */
                if (rrd_parse_print(argv[i],&eaten,gdp,im)) return;
                break;
@@ -596,9 +823,21 @@ rrd_graph_script(int argc, char *argv[], image_desc_t *im, int optno) {
            case GF_HRULE:      /* value#color[:legend] */
            case GF_LINE:       /* vname-or-value[#color[:legend]][:STACK] */
            case GF_AREA:       /* vname-or-value[#color[:legend]][:STACK] */
-           case GF_STACK:      /* vname-or-value[#color[:legend]] */
            case GF_TICK:       /* vname#color[:num[:legend]] */
-               if (rrd_parse_PVHLAST(argv[i],&eaten,gdp,im)) return;
+               if (rrd_parse_PVHLAST(argv[i],&eaten,gdp,im))return;
+                last_gf = gdp->gf;
+                last_linewidth = gdp->linewidth;
+               break;
+           case GF_STACK:      /* vname-or-value[#color[:legend]] */           
+               if (rrd_parse_PVHLAST(argv[i],&eaten,gdp,im))return;
+                if (last_gf == GF_LINE || last_gf == GF_AREA){
+                   gdp->gf = last_gf;
+                   gdp->linewidth = last_linewidth;
+                } else {
+                   rrd_set_error("STACK must follow LINE or AREA! command:\n%s",
+                        &argv[i][eaten],argv[i]);
+                   return;
+                }
                break;
        /* data acquisition */
            case GF_DEF:        /* vname=x:DS:CF:[:step=#][:start=#][:end=#] */
index d6d1935f34c566942dc330077e33aced4b01a62d..dccde506c8fab42a9c8727d011652292eb012bf1 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_hw.c : Support for Holt-Winters Smoothing/ Aberrant Behavior Detection
  *****************************************************************************
@@ -474,7 +474,7 @@ erase_violations(rrd_t *rrd, unsigned long cdp_idx, unsigned long rra_idx)
    {
 #ifdef DEBUG
          fprintf(stderr,"erase_violations called for non-FAILURES RRA: %s\n",
-            rrd -> rra_def[rra_idx].cf);
+            rrd -> rra_def[rra_idx].cf_nam);
 #endif
          return;
    }
index 7cba2262df21231023a663c09038c5f6c9c7c39c..89220b4f50ba1ac688be23dc536223901d825ff8 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.0.33  Copyright Tobias Oetiker, 1997 - 2000
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_hw.h : Support for Holt-Winters Smoothing/ Aberrant Behavior Detection
  *****************************************************************************/
index c183f7c44934c15305d9f11388fa8e7a8d8f40a7..d5ccbc5b5b547a584130bb213c9b00cd6081e620 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_info  Get Information about the configuration of an RRD
  *****************************************************************************/
@@ -117,7 +117,7 @@ rrd_info_r(char *filename) {
     switch (current_ds) {
           case DST_CDEF:
                  {
-                 char *buffer = 0;
+                 char *buffer = NULL;
                  rpn_compact2str((rpn_cdefds_t *) &(rrd.ds_def[i].par[DS_cdef]),
                         rrd.ds_def, &buffer);
                  info.u_str = buffer;
index eb5ccf591c9e10ffd1250dc13ca82a7e6c4a6e54..6fe480eb2f75ebb5489e4f36d6927fda706a4698 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  * This file:     Copyright 2003 Peter Stamfest <peter@stamfest.at> 
  *                             & Tobias Oetiker
  * Distributed under the GPL
@@ -17,7 +17,10 @@ extern "C" {
 #endif
 
 #undef strerror
+
+#if( 2 < __GNUC__ )
 #pragma GCC poison strtok asctime ctime gmtime localtime tmpnam strerror
+#endif
 
 #ifdef  __cplusplus
 }
index d50e7604b9b44262e7a015c5142d4071064c2383..c4b4b269a1db8a0c7c77f1f7fea6b8dd931ee8a9 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_last.c
  *****************************************************************************
diff --git a/src/rrd_lastupdate.c b/src/rrd_lastupdate.c
new file mode 100644 (file)
index 0000000..169c49d
--- /dev/null
@@ -0,0 +1,54 @@
+/*****************************************************************************
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
+ *****************************************************************************
+ * rrd_lastupdate  Get the last datum entered for each DS
+ *****************************************************************************/
+
+#include "rrd_tool.h"
+#include "rrd_rpncalc.h"
+#include <stdarg.h>
+
+int
+rrd_lastupdate(int argc, char **argv, time_t *last_update,
+                 unsigned long *ds_cnt, char ***ds_namv, char ***last_ds) {
+    unsigned long i=0;
+    char        *filename;
+    FILE         *in_file;
+    rrd_t        rrd;
+
+    if(argc < 2){
+        rrd_set_error("please specify an rrd");
+        return -1;
+    }
+    filename = argv[1];
+
+    if(rrd_open(filename,&in_file,&rrd, RRD_READONLY)==-1){
+       return(-1);
+    }
+    fclose(in_file);
+
+    *last_update=rrd.live_head->last_up;
+    *ds_cnt = rrd.stat_head->ds_cnt;
+    if (((*ds_namv) =
+               (char **) malloc(rrd.stat_head->ds_cnt * sizeof(char*)))==NULL){
+        rrd_set_error("malloc fetch ds_namv array");
+       rrd_free(&rrd);
+       return(-1);
+    } 
+
+    if (((*last_ds) =
+               (char **) malloc(rrd.stat_head->ds_cnt * sizeof(char*)))==NULL){
+        rrd_set_error("malloc fetch last_ds array");
+       rrd_free(&rrd);
+       free(*ds_namv);
+       return(-1);
+    } 
+
+    for(i=0;i<rrd.stat_head->ds_cnt;i++){
+       (*ds_namv)[i] = sprintf_alloc("%s", rrd.ds_def[i].ds_nam);
+       (*last_ds)[i] = sprintf_alloc("%s", rrd.pdp_prep[i].last_ds);
+    }
+
+    rrd_free(&rrd);
+    return(0); 
+}
index ce0873e5ed37003c7e4c12dd7ae29866870aae0a..2a5ac1455cd3c50b57fca647b5e59fcf99a477bc 100644 (file)
@@ -1,15 +1,32 @@
 #include "rrd_nan_inf.h"
 
-#if defined(WIN32)
+int done_nan = 0;
+int done_inf = 0;
 
+double dnan;
+double dinf;
+
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
 #include <math.h>
 
-double set_to_DNAN(void) { return (double)fmod(0.0,0.0); }
-double set_to_DINF(void) { return (double)fabs((double)log(0.0)); }
+#define NAN_FUNC (double)fmod(0.0,0.0)
+#define INF_FUNC (double)fabs((double)log(0.0))
 
 #else
 
-double set_to_DNAN(void) { return (double)(0.0/0.0); }
-double set_to_DINF(void) { return (double)(1.0/0.0); }
+#define NAN_FUNC (double)(0.0/0.0)
+#define INF_FUNC (double)(1.0/0.0)
 
 #endif
+
+double set_to_DNAN(void)
+{
+  if ( !done_nan ) { dnan = NAN_FUNC; done_nan = 1; }
+  return dnan;
+}
+
+double set_to_DINF(void)
+{
+  if ( !done_inf ) { dinf = INF_FUNC; done_inf = 1; }
+  return dinf;
+}
index 8cdc00e54b289cecec0eb580c9a73838aacefa4c..b2b5227b7409a1d8efea46601bd266bd89d3debb 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  * This file:     Copyright 2003 Peter Stamfest <peter@stamfest.at> 
  *                             & Tobias Oetiker
  * Distributed under the GPL
 #define MAXLEN 4096
 #define ERRBUFLEN 256
 
-static char rrd_error[MAXLEN] = "\0";
-static char rrd_liberror[ERRBUFLEN] = "\0";
+static char rrd_error[MAXLEN+10];
+static char rrd_liberror[ERRBUFLEN+10];
+static int  rrd_context_init = 0;
 /* The global context is very useful in the transition period to even
    more thread-safe stuff, it can be used whereever we need a context
    and do not need to worry about concurrency. */
 static struct rrd_context global_ctx = {
-    sizeof(rrd_error),
-    sizeof(rrd_liberror),
+    MAXLEN,
+    ERRBUFLEN,
     rrd_error, 
     rrd_liberror
 };
-#include <stdarg.h>
+/* #include <stdarg.h> */
 
-struct rrd_context *rrd_get_context() {
+struct rrd_context *rrd_get_context(void) {
+    if (! rrd_context_init ){
+       rrd_context_init = 1;
+        global_ctx.rrd_error[0]='\0';
+        global_ctx.lib_errstr[0]='\0';
+    }
     return &global_ctx;
 }
 
index 66d1865e7d3562e2e62e8479b93c3ad5d69434e9..3740750fb73e6839ead4d5c7a13a54e02547ad1c 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_open.c  Open an RRD File
  *****************************************************************************
@@ -78,83 +78,99 @@ rrd_open(const char *file_name, FILE **in_file, rrd_t *rrd, int rdwr)
     
     rrd_init(rrd);
     if (rdwr == RRD_READONLY) {
-#ifndef WIN32
-       mode = "r";
-#else
-       mode = "rb";
-#endif
+        mode = "rb";
     } else {
-#ifndef WIN32
-       mode = "r+";
-#else
-       mode = "rb+";
-#endif
+        mode = "rb+";
     }
     
     if (((*in_file) = fopen(file_name,mode)) == NULL ){
-       rrd_set_error("opening '%s': %s",file_name, rrd_strerror(errno));
-       return (-1);
+        rrd_set_error("opening '%s': %s",file_name, rrd_strerror(errno));
+        return (-1);
     }
+
+#ifdef HAVE_POSIX_FADVISE
+    /* In general we need no read-ahead when dealing with rrd_files.
+       When we stop reading, it is highly unlikely that we start up again.
+       In this manner we actually save time and diskaccess (and buffer cache).
+       Thanks to Dave Plonka for the Idea of using POSIX_FADV_RANDOM here. */       
+    if (0 != posix_fadvise(fileno(*in_file), 0, 0, POSIX_FADV_RANDOM)) {
+        rrd_set_error("setting POSIX_FADV_RANDOM on '%s': %s",file_name, rrd_strerror(errno));
+        fclose(*in_file);
+        return(-1);
+     }    
+#endif
+
 /*
-       if (rdwr == RRD_READWRITE)
-       {
-          if (setvbuf((*in_file),NULL,_IONBF,2)) {
-                 rrd_set_error("failed to disable the stream buffer\n");
-                 return (-1);
-          }
-       }
+        if (rdwr == RRD_READWRITE)
+        {
+           if (setvbuf((*in_file),NULL,_IONBF,2)) {
+                  rrd_set_error("failed to disable the stream buffer\n");
+                  return (-1);
+           }
+        }
 */
     
 #define MYFREAD(MYVAR,MYVART,MYCNT) \
     if ((MYVAR = malloc(sizeof(MYVART) * MYCNT)) == NULL) {\
-       rrd_set_error("" #MYVAR " malloc"); \
+        rrd_set_error("" #MYVAR " malloc"); \
         fclose(*in_file); \
-    return (-1); } \
+        return (-1); } \
     fread(MYVAR,sizeof(MYVART),MYCNT, *in_file); 
 
 
     MYFREAD(rrd->stat_head, stat_head_t,  1)
-    version = atoi(rrd->stat_head->version);
+    /* lets see if the first read worked */
+    if (ferror( *in_file ) || feof(*in_file)) {
+        rrd_set_error("reading the cookie off %s faild",file_name);
+        fclose(*in_file);
+        return(-1);
+    }        
+
+        /* lets do some test if we are on track ... */
+        if (strncmp(rrd->stat_head->cookie,RRD_COOKIE,4) != 0){
+            rrd_set_error("'%s' is not an RRD file",file_name);
+            free(rrd->stat_head);
+            rrd->stat_head = NULL; 
+            fclose(*in_file);
+            return(-1);}
+
+        if (rrd->stat_head->float_cookie != FLOAT_COOKIE){
+            rrd_set_error("This RRD was created on other architecture");
+            free(rrd->stat_head);
+            rrd->stat_head = NULL; 
+            fclose(*in_file);
+            return(-1);}
 
-       /* lets do some test if we are on track ... */
-       if (strncmp(rrd->stat_head->cookie,RRD_COOKIE,4) != 0){
-           rrd_set_error("'%s' is not an RRD file",file_name);
-           free(rrd->stat_head);
-           fclose(*in_file);
-           return(-1);}
+    version = atoi(rrd->stat_head->version);
 
         if (version > atoi(RRD_VERSION)){
-           rrd_set_error("can't handle RRD file version %s",
-                       rrd->stat_head->version);
-           free(rrd->stat_head);
-           fclose(*in_file);
-           return(-1);}
-
-       if (rrd->stat_head->float_cookie != FLOAT_COOKIE){
-           rrd_set_error("This RRD was created on other architecture");
-           free(rrd->stat_head);
-           fclose(*in_file);
-           return(-1);}
+            rrd_set_error("can't handle RRD file version %s",
+                        rrd->stat_head->version);
+            free(rrd->stat_head);
+            rrd->stat_head = NULL; 
+            fclose(*in_file);
+            return(-1);}
+
 
     MYFREAD(rrd->ds_def,    ds_def_t,     rrd->stat_head->ds_cnt)
     MYFREAD(rrd->rra_def,   rra_def_t,    rrd->stat_head->rra_cnt)
     /* handle different format for the live_head */
     if(version < 3) {
-           rrd->live_head = (live_head_t *)malloc(sizeof(live_head_t));
-           if(rrd->live_head == NULL) {
-               rrd_set_error("live_head_t malloc");
-               fclose(*in_file); 
-               return (-1);
-           }
-               fread(&rrd->live_head->last_up, sizeof(long), 1, *in_file); 
-               rrd->live_head->last_up_usec = 0;
+            rrd->live_head = (live_head_t *)malloc(sizeof(live_head_t));
+            if(rrd->live_head == NULL) {
+                rrd_set_error("live_head_t malloc");
+                fclose(*in_file); 
+                return (-1);
+            }
+                fread(&rrd->live_head->last_up, sizeof(long), 1, *in_file); 
+                rrd->live_head->last_up_usec = 0;
     }
     else {
-           MYFREAD(rrd->live_head, live_head_t, 1)
+            MYFREAD(rrd->live_head, live_head_t, 1)
     }
     MYFREAD(rrd->pdp_prep,  pdp_prep_t,   rrd->stat_head->ds_cnt)
     MYFREAD(rrd->cdp_prep,  cdp_prep_t,   (rrd->stat_head->rra_cnt
-                                            * rrd->stat_head->ds_cnt))
+                                             * rrd->stat_head->ds_cnt))
     MYFREAD(rrd->rra_ptr,   rra_ptr_t,    rrd->stat_head->rra_cnt)
 #undef MYFREAD
 
@@ -201,8 +217,8 @@ int readfile(const char *file_name, char **buffer, int skipfirst){
     if ((strcmp("-",file_name) == 0)) { input = stdin; }
     else {
       if ((input = fopen(file_name,"rb")) == NULL ){
-       rrd_set_error("opening '%s': %s",file_name,rrd_strerror(errno));
-       return (-1);
+        rrd_set_error("opening '%s': %s",file_name,rrd_strerror(errno));
+        return (-1);
       }
     }
     if (skipfirst){
@@ -213,21 +229,21 @@ int readfile(const char *file_name, char **buffer, int skipfirst){
       /* have extra space for detecting EOF without realloc */
       totalcnt = (ftell(input) + 1) / sizeof(char) - offset;
       if (totalcnt < MEMBLK)
-       totalcnt = MEMBLK; /* sanitize */
+        totalcnt = MEMBLK; /* sanitize */
       fseek(input, offset * sizeof(char), SEEK_SET);
     }
     if (((*buffer) = (char *) malloc((totalcnt+4) * sizeof(char))) == NULL) {
-       perror("Allocate Buffer:");
-       exit(1);
+        perror("Allocate Buffer:");
+        exit(1);
     };
     do{
       writecnt += fread((*buffer)+writecnt, 1, (totalcnt - writecnt) * sizeof(char),input);
       if (writecnt >= totalcnt){
-       totalcnt += MEMBLK;
-       if (((*buffer)=rrd_realloc((*buffer), (totalcnt+4) * sizeof(char)))==NULL){
-           perror("Realloc Buffer:");
-           exit(1);
-       };
+        totalcnt += MEMBLK;
+        if (((*buffer)=rrd_realloc((*buffer), (totalcnt+4) * sizeof(char)))==NULL){
+            perror("Realloc Buffer:");
+            exit(1);
+        };
       }
     } while (! feof(input));
     (*buffer)[writecnt] = '\0';
index 6b1648e2dbd62b765384e79e8943a7af1862b525..c1bdda2348fc3a2e31f23b597001166051e16e79 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_resize.c Alters size of an RRA
  *****************************************************************************
 int
 rrd_resize(int argc, char **argv)
 {
-    char             *infilename,outfilename[11]="resize.rrd";
-    FILE             *infile,*outfile;
-    rrd_t             rrdold,rrdnew;
-    rrd_value_t       buffer;
-    unsigned long     l,rra;
-    long              modify;
-    unsigned long     target_rra;
-    int               grow=0,shrink=0;
-    char             *endptr;
+    char               *infilename,outfilename[11]="resize.rrd";
+    FILE               *infile,*outfile;
+    rrd_t              rrdold,rrdnew;
+    rrd_value_t                buffer;
+    int                        version;
+    unsigned long      l,rra;
+    long               modify;
+    unsigned long      target_rra;
+    int                        grow=0,shrink=0;
+    char               *endptr;
 
     infilename=argv[1];
     if (!strcmp(infilename,"resize.rrd")) {
@@ -84,6 +85,19 @@ rrd_resize(int argc, char **argv)
     rrdnew.cdp_prep  = rrdold.cdp_prep;
     rrdnew.rra_ptr   = rrdold.rra_ptr;
 
+    version = atoi(rrdold.stat_head->version);
+    switch (version) {
+       case 3: break;
+       case 1: rrdold.stat_head->version[3]='3';
+               break;
+       default: {
+               rrd_set_error("Do not know how to handle RRD version %s",rrdold.stat_head->version);
+               rrd_free(&rrdold);      
+               fclose(infile);
+               return(-1);
+               }
+    }
+
     if ((outfile=fopen(outfilename,"wb"))==NULL) {
         rrd_set_error("Can't create '%s'",outfilename);
         return(-1);
index 817195b65d6301ac2d6da6355d23b86a0f64acb0..1da3a591f7a2c608b31f63cefe29858b534b71a7 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2004
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_restore.c  creates new rrd from data dumped by rrd_dump.c
  *****************************************************************************/
@@ -8,7 +8,7 @@
 #include "rrd_rpncalc.h"
 #include <fcntl.h>
 
-#ifdef WIN32
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
 #include <io.h>
 #define open _open
 #define close _close
@@ -18,6 +18,7 @@
 
 void xml_lc(char*);
 int skip(char **);
+int skipxml(char **);
 int eat_tag(char **, char *);
 int read_tag(char **, char *, char *, void *);
 int xml2rrd(char*, rrd_t*, char);
@@ -44,9 +45,29 @@ void xml_lc(char* buf){
   }
 }
 
-int skip(char **buf){
+int skipxml(char **buf){
   char *ptr;  
   ptr=(*buf);
+  do {
+    (*buf)=ptr;
+    while((*(ptr+1)) && ((*ptr)==' ' ||  (*ptr)=='\r' || (*ptr)=='\n' || (*ptr)=='\t')) ptr++;
+    if (strncmp(ptr,"<?xml",4) == 0) {
+      ptr= strstr(ptr,"?>");
+      if (ptr) ptr+=2; else {
+       rrd_set_error("Dangling XML header");
+       (*buf) = NULL;
+       return -1;
+      }
+    }
+  } while ((*buf)!=ptr);  
+  return 1;
+}
+
+int skip(char **buf){
+  char *ptr;
+  if ((buf == NULL) || (*buf == NULL))
+    return -1;  
+  ptr=(*buf);
   do {
     (*buf)=ptr;
     while((*(ptr+1)) && ((*ptr)==' ' ||  (*ptr)=='\r' || (*ptr)=='\n' || (*ptr)=='\t')) ptr++;
@@ -112,11 +133,14 @@ int xml2rrd(char* buf, rrd_t* rrd, char rc){
   char *ptr,*ptr2,*ptr3; /* walks thought the buffer */
   long rows=0,mempool=0,i=0;
   int rra_index;
+  int input_version;
   xml_lc(buf); /* lets lowercase all active parts of the xml */
   ptr=buf;
   ptr2=buf;
   ptr3=buf;
   /* start with an RRD tag */
+  
+  skipxml(&ptr);
 
   eat_tag(&ptr,"rrd");
   /* allocate static header */
@@ -127,20 +151,25 @@ int xml2rrd(char* buf, rrd_t* rrd, char rc){
 
   strcpy(rrd->stat_head->cookie,RRD_COOKIE);
   read_tag(&ptr,"version","%4[0-9]",rrd->stat_head->version);
+  input_version = atoi(rrd->stat_head->version);
   /* added primitive version checking */
-  if (atoi(rrd -> stat_head -> version) > atoi(RRD_VERSION) )
+  if (input_version > atoi(RRD_VERSION) || input_version < 1)
   {
-    rrd_set_error("Incompatible file version, detected version %s is bigger than supported version %s\n",
+    rrd_set_error("Incompatible file version, detected version %s. This is not supported by the version %s restore tool.\n",
                  rrd -> stat_head -> version, RRD_VERSION );
-    free(rrd -> stat_head);
+    free(rrd -> stat_head); 
+    rrd->stat_head = NULL; 
     return -1;
   }
-  if (atoi(rrd -> stat_head -> version) < 2) 
+  /* make sure we output the right version */
+  strcpy(rrd->stat_head->version,RRD_VERSION);
+
+  /*  if (atoi(rrd -> stat_head -> version) < 2) 
   {
-    rrd_set_error("Can only restore version >= 2 (Not %s). Dump your rrd using a current rrdtool dump.",  rrd -> stat_head -> version );
-    free(rrd -> stat_head);
+    rrd_set_error("Can only restore version >= 2 (Not %s). Dump your old rrd using a current rrdtool dump.",  rrd -> stat_head -> version );
     return -1;
-  }
+  } */
+
   rrd->stat_head->float_cookie = FLOAT_COOKIE;
   rrd->stat_head->ds_cnt = 0;
   rrd->stat_head->rra_cnt = 0;
@@ -185,8 +214,9 @@ int xml2rrd(char* buf, rrd_t* rrd, char rc){
       read_tag(&ptr2,"max","%lf",&(rrd->ds_def[rrd->stat_head->ds_cnt-1].par[DS_max_val].u_val));
          } else { /* DST_CDEF */
                 char buffer[1024];
-            read_tag(&ptr2,"cdef","%s",buffer);
+                read_tag(&ptr2,"cdef","%1000s",buffer);
                 parseCDEF_DS(buffer,rrd,rrd -> stat_head -> ds_cnt - 1);
+                if (rrd_test_error()) return -1;
          }
 
       read_tag(&ptr2,"last_ds","%30s",rrd->pdp_prep[rrd->stat_head->ds_cnt-1].last_ds);
@@ -209,7 +239,7 @@ int xml2rrd(char* buf, rrd_t* rrd, char rc){
       if((rrd->cdp_prep = rrd_realloc(rrd->cdp_prep,
                                  rrd->stat_head->rra_cnt
                                  *rrd->stat_head->ds_cnt*sizeof(cdp_prep_t)))==NULL){
-         rrd_set_error("allocating cdp_prep"); return -1; }
+         rrd_set_error("allocating cdp_prep"); return -1; }
 
       memset(&(rrd->cdp_prep[rrd->stat_head->ds_cnt*(rrd->stat_head->rra_cnt-1)]), 
             0, rrd->stat_head->ds_cnt*sizeof(cdp_prep_t));
@@ -221,12 +251,19 @@ int xml2rrd(char* buf, rrd_t* rrd, char rc){
 
       read_tag(&ptr2,"pdp_per_row","%lu",&(rrd->rra_def[rrd->stat_head->rra_cnt-1].pdp_cnt));
       /* support to read RRA parameters */
-      eat_tag(&ptr2, "params");
-      skip(&ptr2);
       rra_index = rrd->stat_head->rra_cnt - 1;
-      /* backwards compatibility w/ old patch */
+      if ( input_version < 2 ){
+         read_tag(&ptr2, "xff","%lf",
+            &(rrd->rra_def[rra_index].par[RRA_cdp_xff_val].u_val));
+      } else {
+        if (eat_tag(&ptr2, "params") != 1) {
+         rrd_set_error("could not find params tag to eat and skip");
+          return -1;
+        }
+        skip(&ptr2);
+        /* backwards compatibility w/ old patch */
       if (strncmp(ptr2, "<value>",7) == 0) {
-         parse_patch1028_RRA_params(&ptr2,rrd,rra_index); 
+          parse_patch1028_RRA_params(&ptr2,rrd,rra_index); 
       } else {
       switch(cf_conv(rrd -> rra_def[rra_index].cf_nam)) {
       case CF_HWPREDICT:
@@ -270,6 +307,9 @@ int xml2rrd(char* buf, rrd_t* rrd, char rc){
       }
       }
       eat_tag(&ptr2, "/params");
+   }
+
+
       eat_tag(&ptr2,"cdp_prep");
       for(i=0;i< (int)rrd->stat_head->ds_cnt;i++)
       {
@@ -277,6 +317,15 @@ int xml2rrd(char* buf, rrd_t* rrd, char rc){
       /* support to read CDP parameters */
       rra_index = rrd->stat_head->rra_cnt-1; 
       skip(&ptr2);
+      if ( input_version < 2 ){
+          rrd->cdp_prep[rrd->stat_head->ds_cnt*(rra_index)+i].scratch[CDP_primary_val].u_val = 0.0;
+          rrd->cdp_prep[rrd->stat_head->ds_cnt*(rra_index)+i].scratch[CDP_secondary_val].u_val = 0.0;
+          read_tag(&ptr2,"value","%lf",&(rrd->cdp_prep[rrd->stat_head->ds_cnt
+               *(rra_index) +i].scratch[CDP_val].u_val));
+          read_tag(&ptr2,"unknown_datapoints","%lu",&(rrd->cdp_prep[rrd->stat_head->ds_cnt
+              *(rra_index) +i].scratch[CDP_unkn_pdp_cnt].u_cnt));
+      } else {
+
       if (strncmp(ptr2, "<value>",7) == 0) {
          parse_patch1028_CDP_params(&ptr2,rrd,rra_index,i);
       } else {
@@ -336,6 +385,7 @@ int xml2rrd(char* buf, rrd_t* rrd, char rc){
             break;
         }
       }
+      }
       eat_tag(&ptr2,"/ds");
       }
       eat_tag(&ptr2,"/cdp_prep");
@@ -421,7 +471,7 @@ rrd_write(char *file_name, rrd_t *rrd, char force_overwrite)
     if (strcmp("-",file_name)==0){
       rrd_file= stdout;
     } else {
-#ifdef WIN32
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
       fdflags = O_RDWR|O_BINARY|O_CREAT;
 #else
       fdflags = O_WRONLY|O_CREAT;
@@ -446,11 +496,7 @@ rrd_write(char *file_name, rrd_t *rrd, char force_overwrite)
     fwrite(rrd->rra_def,
           sizeof(rra_def_t), rrd->stat_head->rra_cnt, rrd_file);
 
-        /* maybe the xml hold an old formatted rrd */
-    if (atoi(rrd->stat_head->version) < 3)
-      fwrite(&(rrd->live_head->last_up), sizeof(long),1, rrd_file);
-    else
-      fwrite(rrd->live_head, sizeof(live_head_t),1, rrd_file);
+    fwrite(rrd->live_head, sizeof(live_head_t),1, rrd_file);
 
     fwrite( rrd->pdp_prep, sizeof(pdp_prep_t),rrd->stat_head->ds_cnt,rrd_file);
     
@@ -488,24 +534,19 @@ rrd_restore(int argc, char **argv)
        char                    force_overwrite = 0;    
 
     /* init rrd clean */
-    rrd_init(&rrd);
-    if (argc<3) {
-               rrd_set_error("usage rrdtool %s [--range-check/-r] [--force-overwrite/-f] file.xml file.rrd",argv[0]);
-               return -1;
-    }
-       
+    optind = 0; opterr = 0;  /* initialize getopt */
        while (1) {
                static struct option long_options[] =
                {
-                       {"range-check",      required_argument, 0,  'r'},
-                       {"force-overwrite",     required_argument, 0,   'f'},
+                       {"range-check",      no_argument, 0,  'r'},
+                       {"force-overwrite",  no_argument, 0,  'f'},
                        {0,0,0,0}
                };
                int option_index = 0;
                int opt;
                
                
-               opt = getopt_long(argc, argv, "r:f", long_options, &option_index);
+               opt = getopt_long(argc, argv, "rf", long_options, &option_index);
                
                if (opt == EOF)
                        break;
@@ -523,16 +564,26 @@ rrd_restore(int argc, char **argv)
                        break;
                }
     }
+
+    if (argc-optind != 2) {
+               rrd_set_error("usage rrdtool %s [--range-check/-r] [--force-overwrite/-f] file.xml file.rrd",argv[0]);
+               return -1;
+    }
        
     if (readfile(argv[optind],&buf,0)==-1){
       return -1;
     }
+
+    rrd_init(&rrd);
+
     if (xml2rrd(buf,&rrd,rc)==-1) {
        rrd_free(&rrd);
        free(buf);
        return -1;
     }
+
     free(buf);
+
     if(rrd_write(argv[optind+1],&rrd,force_overwrite)==-1){
        rrd_free(&rrd); 
        return -1;      
index 3cd582b66824cc8fd4dc17e353ab1fb2941d15d1..eb7c94b2e5be67d8dd74afd2e7d060ee01bbc824 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * RRDtool 1.0.28  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  ****************************************************************************
  * rrd_rpncalc.c  RPN calculator functions
  ****************************************************************************/
@@ -97,7 +97,7 @@ void rpn_compact2str(rpn_cdefds_t *rpnc,ds_def_t *ds_def,char **str)
         
         if (rpnc[i].op == OP_NUMBER) {
             /* convert a short into a string */
-#ifdef WIN32
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
             _itoa(rpnc[i].val,buffer,10);
 #else
             sprintf(buffer,"%d",rpnc[i].val);
@@ -153,11 +153,16 @@ void rpn_compact2str(rpn_cdefds_t *rpnc,ds_def_t *ds_def,char **str)
          add_op(OP_NOW,NOW)
          add_op(OP_LTIME,LTIME)
          add_op(OP_TIME,TIME)
+         add_op(OP_ATAN2,ATAN2)
          add_op(OP_ATAN,ATAN)
          add_op(OP_SQRT,SQRT)
          add_op(OP_SORT,SORT)
          add_op(OP_REV,REV)
          add_op(OP_TREND,TREND)
+         add_op(OP_RAD2DEG,RAD2DEG)
+         add_op(OP_DEG2RAD,DEG2RAD)
+         add_op(OP_AVG,AVG)
+         add_op(OP_ABS,ABS)
 #undef add_op
               }
     (*str)[offset] = '\0';
@@ -183,7 +188,7 @@ short addop2str(enum op_en op, enum op_en op_type, char *op_str,
     return 0;
 }
 
-void parseCDEF_DS(char *def,rrd_t *rrd, int ds_idx)
+void parseCDEF_DS(const char *def,rrd_t *rrd, int ds_idx)
 {
     rpnp_t *rpnp = NULL;
     rpn_cdefds_t *rpnc = NULL;
@@ -191,7 +196,7 @@ void parseCDEF_DS(char *def,rrd_t *rrd, int ds_idx)
     
     rpnp = rpn_parse((void*) rrd, def, &lookup_DS);
     if (rpnp == NULL) {
-        rrd_set_error("failed to parse computed data source %s", def);
+        rrd_set_error("failed to parse computed data source");
         return;
     }
     /* Check for OP nodes not permitted in COMPUTE DS.
@@ -249,13 +254,15 @@ long lookup_DS(void *rrd_vptr,char *ds_name)
  * lookup(): a function that retrieves a numeric key given a variable name
  */
 rpnp_t * 
-rpn_parse(void *key_hash,char *expr,long (*lookup)(void *,char*)){
+rpn_parse(void *key_hash,const char *const expr_const,long (*lookup)(void *,char*)){
     int pos=0;
+    char *expr;
     long steps=-1;    
     rpnp_t  *rpnp;
-    char vname[30];
+    char vname[MAX_VNAME_LEN+10];
     
     rpnp=NULL;
+    expr=(char *)expr_const;
     
     while(*expr){
        if ((rpnp = (rpnp_t *) rrd_realloc(rpnp, (++steps + 2)* 
@@ -269,9 +276,9 @@ rpn_parse(void *key_hash,char *expr,long (*lookup)(void *,char*)){
        } 
        
 #define match_op(VV,VVV) \
-        else if (strncmp(expr, #VVV, strlen(#VVV))==0){ \
-           rpnp[steps].op = VV; \
-           expr+=strlen(#VVV); \
+        else if (strncmp(expr, #VVV, strlen(#VVV))==0 && ( expr[strlen(#VVV)] == ',' || expr[strlen(#VVV)] == '\0' )){ \
+            rpnp[steps].op = VV; \
+            expr+=strlen(#VVV); \
        }
 
 
@@ -325,11 +332,16 @@ rpn_parse(void *key_hash,char *expr,long (*lookup)(void *,char*)){
        match_op(OP_ISINF,ISINF)
        match_op(OP_NOW,NOW)
        match_op(OP_TIME,TIME)
+       match_op(OP_ATAN2,ATAN2)
        match_op(OP_ATAN,ATAN)
        match_op(OP_SQRT,SQRT)
        match_op(OP_SORT,SORT)
        match_op(OP_REV,REV)
        match_op(OP_TREND,TREND)
+       match_op(OP_RAD2DEG,RAD2DEG)
+       match_op(OP_DEG2RAD,DEG2RAD)
+       match_op(OP_AVG,AVG)
+       match_op(OP_ABS,ABS)
 #undef match_op
 
 
@@ -428,7 +440,8 @@ rpn_calc(rpnp_t *rpnp, rpnstack_t *rpnstack, long data_idx,
                rpnstack -> s[++stptr] = rpnp[rpi].val;
                break;
            case OP_VARIABLE:
-               /* Sanity check: VDEFs shouldn't make it here */
+            case OP_PREV_OTHER:
+           /* Sanity check: VDEFs shouldn't make it here */
                if (rpnp[rpi].ds_cnt == 0) {
                    rrd_set_error("VDEF made it into rpn_calc... aborting");
                    return -1;
@@ -439,7 +452,16 @@ rpn_calc(rpnp_t *rpnp, rpnstack_t *rpnstack, long data_idx,
                     * row in the rra (skip over non-relevant
                     * data sources)
                     */
-                   rpnstack -> s[++stptr] =  *(rpnp[rpi].data);
+                   if (rpnp[rpi].op == OP_VARIABLE) {
+                       rpnstack -> s[++stptr] =  *(rpnp[rpi].data);
+                   } else {
+                       if ((output_idx) <= 0) {
+                           rpnstack -> s[++stptr] = DNAN;
+                       } else {                            
+                           rpnstack -> s[++stptr] =  *(rpnp[rpi].data-rpnp[rpi].ds_cnt);
+                       }
+                      
+                   }              
                    if (data_idx % rpnp[rpi].step == 0){
                        rpnp[rpi].data += rpnp[rpi].ds_cnt;
                    }
@@ -454,15 +476,8 @@ rpn_calc(rpnp_t *rpnp, rpnstack_t *rpnstack, long data_idx,
                } else {
                    rpnstack -> s[++stptr] = output[output_idx-1];
                }
-               break;
-       case OP_PREV_OTHER:
-         if ((output_idx) <= 0) {
-               rpnstack -> s[++stptr] = DNAN;
-         } else {
-               rpnstack -> s[++stptr] = rpnp[rpnp[rpi].ptr].data[output_idx-1];
-         }
-         break;
-           case OP_UNKN:
+               break;
+        case OP_UNKN:
                rpnstack -> s[++stptr] = DNAN; 
                break;
            case OP_INF:
@@ -521,6 +536,21 @@ rpn_calc(rpnp_t *rpnp, rpnstack_t *rpnstack, long data_idx,
                stackunderflow(0);
                rpnstack -> s[stptr] = atan(rpnstack -> s[stptr]);
                break;
+           case OP_RAD2DEG:
+               stackunderflow(0);
+               rpnstack -> s[stptr] = 57.29577951 * rpnstack -> s[stptr];
+               break;
+           case OP_DEG2RAD:
+               stackunderflow(0);
+               rpnstack -> s[stptr] = 0.0174532952 * rpnstack -> s[stptr];
+               break;
+           case OP_ATAN2:
+               stackunderflow(1);
+               rpnstack -> s[stptr-1]= atan2(
+                               rpnstack -> s[stptr-1],
+                               rpnstack -> s[stptr]);
+               stptr--;
+               break;
            case OP_COS:
                stackunderflow(0);
                rpnstack -> s[stptr] = cos(rpnstack -> s[stptr]);
@@ -729,6 +759,32 @@ rpn_calc(rpnp_t *rpnp, rpnstack_t *rpnstack, long data_idx,
                        rpnstack -> s[--stptr] = DNAN;
                }
                break;
+           case OP_AVG:
+               stackunderflow(0);
+                {
+                   int i=(int)rpnstack -> s[stptr--];
+                   double sum=0;
+                   int count=0;
+                   stackunderflow(i-1);
+                   while(i>0) {
+                     double val=rpnstack -> s[stptr--];
+                     i--;
+                    if (isnan(val)) { continue; }
+                     count++;
+                     sum+=val;
+                   }
+                   /* now push the result back on stack */
+                   if (count>0) {
+                     rpnstack -> s[++stptr]=sum/count;
+                   } else {
+                     rpnstack -> s[++stptr]=DNAN;
+                   }
+                }
+                break;
+            case OP_ABS:
+                stackunderflow(0);
+                rpnstack -> s[stptr] = fabs(rpnstack -> s[stptr]);
+                break;
            case OP_END:
                break;
        }
index 39909a600207ebadbb9c80e3ceb77485f35f9e2d..17264dcc6ec495b04483061eadff49756af53f13 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * RRDtool 1.0.33  Copyright Tobias Oetiker, 1997 - 2000
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  ****************************************************************************
  * rrd_rpncalc.h  RPN calculator functions
  ****************************************************************************/
@@ -16,7 +16,9 @@ enum op_en {OP_NUMBER=0,OP_VARIABLE,OP_INF,OP_PREV,OP_NEGINF,
            OP_COS,OP_LOG,OP_EXP,OP_LT,OP_LE,OP_GT,OP_GE,OP_EQ,OP_IF,
            OP_MIN,OP_MAX,OP_LIMIT, OP_FLOOR, OP_CEIL,
            OP_UN,OP_END,OP_LTIME,OP_NE,OP_ISINF,OP_PREV_OTHER,OP_COUNT,
-           OP_ATAN,OP_SQRT,OP_SORT,OP_REV,OP_TREND};
+           OP_ATAN,OP_SQRT,OP_SORT,OP_REV,OP_TREND,
+           OP_ATAN2,OP_RAD2DEG,OP_DEG2RAD,
+           OP_AVG,OP_ABS};
 
 typedef struct rpnp_t {
     enum op_en   op;
@@ -45,13 +47,13 @@ typedef struct rpnstack_t {
 void rpnstack_init(rpnstack_t *rpnstack);
 void rpnstack_free(rpnstack_t *rpnstack);
 
-void parseCDEF_DS(char *def, rrd_t *rrd, int ds_idx);
+void parseCDEF_DS(const char *def, rrd_t *rrd, int ds_idx);
 long lookup_DS(void *rrd_vptr, char *ds_name);
 
 short rpn_compact(rpnp_t *rpnp,rpn_cdefds_t **rpnc,short *count);
 rpnp_t * rpn_expand(rpn_cdefds_t *rpnc);
 void rpn_compact2str(rpn_cdefds_t *rpnc,ds_def_t *ds_def,char **str);
-rpnp_t * rpn_parse(void *key_hash,char *expr, long (*lookup)(void *,char *));
+rpnp_t * rpn_parse(void *key_hash,const char *const expr, long (*lookup)(void *,char *));
 short rpn_calc(rpnp_t *rpnp, rpnstack_t *rpnstack, long data_idx, rrd_value_t *output, int output_idx);
 
 #endif
index bd48ec6c3ec366b27b08fd665eeb306e21e49f3f..74969bd05696105da87fe05aba91d16e87812dc5 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_stat Retreive the header part of an RRD
  *****************************************************************************/
index 89b91d5e73414ccec40cb9c448f79150e6309f09..ca99202ea478f8e6e31b622a94cded0718cf5ca7 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  * This file:     Copyright 2003 Peter Stamfest <peter@stamfest.at> 
  *                             & Tobias Oetiker
  * Distributed under the GPL
@@ -51,7 +51,10 @@ struct rrd_context *rrd_get_context(void) {
 #ifdef HAVE_STRERROR_R
 const char *rrd_strerror(int err) {
     struct rrd_context *ctx = rrd_get_context();
-    return strerror_r(err, ctx->lib_errstr, ctx->errlen);
+    if (strerror_r(err, ctx->lib_errstr, ctx->errlen)) 
+         return "strerror_r faild. sorry!"; 
+    else 
+         return ctx->lib_errstr; 
 }
 #else
 #undef strerror
@@ -61,6 +64,7 @@ const char *rrd_strerror(int err) {
     ctx = rrd_get_context();
     pthread_mutex_lock(&mtx);
     strncpy(ctx->lib_errstr, strerror(err), ctx->errlen);
+    ctx->lib_errstr[ctx->errlen]='\0';
     pthread_mutex_unlock(&mtx);
     return ctx->lib_errstr;
 }
index 337a9941c3616900b952a8f4bb7101e18b0ea0bf..53ebda3da8360fb9ba291f33fcbaf949df2fb0ed 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  * This file:     Copyright 2003 Peter Stamfest <peter@stamfest.at> 
  *                             & Tobias Oetiker
  * Distributed under the GPL
@@ -63,7 +63,8 @@ const char *rrd_strerror(int err) {
 
     EnterCriticalSection(&CriticalSection); 
     strncpy(ctx->lib_errstr, strerror(err), ctx->errlen);
-       LeaveCriticalSection(&CriticalSection); 
+    ctx->lib_errstr[ctx->errlen] = '\0';
+    LeaveCriticalSection(&CriticalSection); 
 
     return ctx->lib_errstr;
 }
index f4cfa11af0e3153cd1f68b3c65237b189319152b..f1eb11618e18b5a4b98dc8b01ddcd0233d675692 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2004
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_tool.c  Startup wrapper
  *****************************************************************************/
@@ -22,20 +22,17 @@ void PrintUsage(char *cmd)
 {
 
     char help_main[] =
-          "RRDtool 1.1.x  Copyright 1997-2004 by Tobias Oetiker <tobi@oetiker.ch>\n"
-#ifndef WIN32
-           "               Compiled " MAKE_TIMESTAMP "\n\n"
-#else
+          "RRDtool " PACKAGE_VERSION "  Copyright 1997-2007 by Tobias Oetiker <tobi@oetiker.ch>\n"
            "               Compiled " __DATE__ " " __TIME__ "\n\n"
-#endif          
           "Usage: rrdtool [options] command command_options\n\n";
 
     char help_list[] =
           "Valid commands: create, update, updatev, graph, dump, restore,\n"
-          "\t\tlast, first, info, fetch, tune, resize, xport\n\n";
+          "\t\tlast, lastupdate, first, info, fetch, tune,\n"
+          "\t\tresize, xport\n\n";
 
     char help_listremote[] =
-           "Valid remote commands: quit, ls, cd, mkdir\n\n";
+           "Valid remote commands: quit, ls, cd, mkdir, pwd\n\n";
 
 
     char help_create[] =
@@ -61,6 +58,11 @@ void PrintUsage(char *cmd)
            "* last - show last update time for RRD\n\n"
            "\trrdtool last filename.rrd\n\n";
 
+    char help_lastupdate[] =
+          "* lastupdate - returns the most recent datum stored for\n"
+          "  each DS in an RRD\n\n"
+          "\trrdtool lastupdate filename.rrd\n\n"; 
+
     char help_first[] =
            "* first - show first update time for RRA within an RRD\n\n"
            "\trrdtool first filename.rrd [--rraindex number]\n\n";
@@ -81,12 +83,12 @@ void PrintUsage(char *cmd)
           "\t\ttime|N:value[:value...]\n\n"
            "\t\tat-time@value[:value...]\n\n"
           "\t\t[ time:value[:value...] ..]\n\n";
-
     char help_fetch[] =
           "* fetch - fetch data out of an RRD\n\n"
           "\trrdtool fetch filename.rrd CF\n"
-          "\t\t[--resolution|-r resolution]\n"
-          "\t\t[--start|-s start] [--end|-e end]\n\n";
+          "\t\t[-r|--resolution resolution]\n"
+          "\t\t[-s|--start start] [-e|--end end]\n\n";
 
 /* break up very large strings (help_graph, help_tune) for ISO C89 compliance*/
 
@@ -94,35 +96,47 @@ void PrintUsage(char *cmd)
           "* graph - generate a graph from one or several RRD\n\n"
           "\trrdtool graph filename [-s|--start seconds] [-e|--end seconds]\n"
           "\t\t[-x|--x-grid x-axis grid and label]\n"
-          "\t\t[--alt-y-grid]\n"
+          "\t\t[-Y|--alt-y-grid]\n"
           "\t\t[-y|--y-grid y-axis grid and label]\n"
           "\t\t[-v|--vertical-label string] [-w|--width pixels]\n"
           "\t\t[-h|--height pixels] [-o|--logarithmic]\n"
           "\t\t[-u|--upper-limit value] [-z|--lazy]\n"
           "\t\t[-l|--lower-limit value] [-r|--rigid]\n"
            "\t\t[-g|--no-legend]\n"
-          "\t\t[-F|--force-rules-legend]\n";
+          "\t\t[-F|--force-rules-legend]\n"
+           "\t\t[-j|--only-graph]\n";
     char help_graph2[] =
-           "\t\t[-j|--only-graph]\n"
-          "\t\t[--font FONTTAG:size:font]\n"
-           "\t\t[--zoom factor]\n"       
-          "\t\t[--alt-autoscale]\n"
-          "\t\t[--alt-autoscale-max]\n"
-          "\t\t[--units-exponent value]\n"        
-          "\t\t[--step seconds]\n"        
+          "\t\t[-n|--font FONTTAG:size:font]\n"
+           "\t\t[-m|--zoom factor]\n"       
+          "\t\t[-A|--alt-autoscale]\n"
+          "\t\t[-M|--alt-autoscale-max]\n"
+          "\t\t[-R|--font-render-mode {normal,light,mono}]\n"
+          "\t\t[-B|--font-smoothing-threshold size]\n"
+          "\t\t[-E|--slope-mode]\n"
+          "\t\t[-N|--no-gridfit]\n"
+          "\t\t[-X|--units-exponent value]\n"
+          "\t\t[-L|--units-length value]\n"
+          "\t\t[-S|--step seconds]\n"     
           "\t\t[-f|--imginfo printfstr]\n"
           "\t\t[-a|--imgformat PNG]\n"
-          "\t\t[-c|--color COLORTAG#rrggbb[aa]] [-t|--title string]\n";
+          "\t\t[-c|--color COLORTAG#rrggbb[aa]] [-t|--title string]\n"
+          "\t\t[-W|--watermark string]\n"
+          "\t\t[DEF:vname=rrd:ds-name:CF]\n";
     char help_graph3[] =
-          "\t\t[DEF:vname=rrd:ds-name:CF]\n"
           "\t\t[CDEF:vname=rpn-expression]\n"
-          "\t\t[PRINT:vname:CF:format]\n"
-          "\t\t[GPRINT:vname:CF:format]\n"
+          "\t\t[VDEF:vdefname=rpn-expression]\n"
+          "\t\t[PRINT:vdefname:format]\n"
+          "\t\t[GPRINT:vdefname:format]\n"
+          "\t\t[COMMENT:text]\n"
+          "\t\t[SHIFT:vname:offset]\n"
+          "\t\t[TICK:vname#rrggbb[aa][:[fraction][:legend]]]\n"
           "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
           "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
-          "\t\t[LINE{1|2|3}:vname[#rrggbb[aa][:legend]]]\n"
-          "\t\t[AREA:vname[#rrggbb[aa][:legend]]]\n"
-          "\t\t[STACK:vname[#rrggbb[aa][:legend]]]\n\n";
+          "\t\t[LINE[width]:vname[#rrggbb[aa][:[legend][:STACK]]]]\n"
+          "\t\t[AREA:vname[#rrggbb[aa][:[legend][:STACK]]]]\n"
+          "\t\t[PRINT:vname:CF:format] (deprecated)\n"
+          "\t\t[GPRINT:vname:CF:format] (deprecated)\n"
+          "\t\t[STACK:vname[#rrggbb[aa][:legend]]] (deprecated)\n\n";
 
     char help_tune1[] =
           " * tune -  Modify some basic properties of an RRD\n\n"
@@ -151,6 +165,7 @@ void PrintUsage(char *cmd)
           "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n"
           "\t\t[-m|--maxrows rows]\n"
           "\t\t[--step seconds]\n"        
+          "\t\t[--enumds]\n"      
           "\t\t[DEF:vname=rrd:ds-name:CF]\n"
           "\t\t[CDEF:vname=rpn-expression]\n"
            "\t\t[XPORT:vname:legend]\n\n";
@@ -171,15 +186,20 @@ void PrintUsage(char *cmd)
           " * mkdir - creates a new directory\n\n"
           "\trrdtool mkdir newdirectoryname\n\n";
 
+    char help_pwd[] =
+          " * pwd - returns the current working directory\n\n"
+          "\trrdtool pwd\n\n";
+
     char help_lic[] =
           "RRDtool is distributed under the Terms of the GNU General\n"
           "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
 
           "For more information read the RRD manpages\n\n";
 
-    enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST, C_FIRST,
-          C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, C_RESIZE, C_XPORT,
-           C_QUIT, C_LS, C_CD, C_MKDIR, C_UPDATEV };
+    enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST,
+          C_LASTUPDATE, C_FIRST, C_UPDATE, C_FETCH, C_GRAPH, C_TUNE,
+          C_RESIZE, C_XPORT, C_QUIT, C_LS, C_CD, C_MKDIR, C_PWD,
+          C_UPDATEV };
 
     int help_cmd = C_NONE;
 
@@ -195,6 +215,8 @@ void PrintUsage(char *cmd)
                help_cmd = C_RESTORE;
            else if (!strcmp(cmd,"last"))
                help_cmd = C_LAST;
+           else if (!strcmp(cmd,"lastupdate"))
+               help_cmd = C_LASTUPDATE;
            else if (!strcmp(cmd,"first"))
                help_cmd = C_FIRST;
            else if (!strcmp(cmd,"update"))
@@ -219,6 +241,8 @@ void PrintUsage(char *cmd)
                 help_cmd = C_CD;
             else if (!strcmp(cmd,"mkdir"))
                 help_cmd = C_MKDIR;
+            else if (!strcmp(cmd,"pwd"))
+                help_cmd = C_PWD;
        }
     fputs(help_main, stdout);
     switch (help_cmd)
@@ -244,6 +268,9 @@ void PrintUsage(char *cmd)
            case C_LAST:
                fputs(help_last, stdout);
                break;
+           case C_LASTUPDATE:
+               fputs(help_lastupdate, stdout);
+               break;
            case C_FIRST:
                fputs(help_first, stdout);
                break;
@@ -283,18 +310,42 @@ void PrintUsage(char *cmd)
            case C_MKDIR:
                fputs(help_mkdir, stdout);
                break;
+           case C_PWD:
+               fputs(help_pwd, stdout);
+               break;
        }
     fputs(help_lic, stdout);
 }
 
+static char *fgetslong(char **aLinePtr, FILE *stream)
+{
+   char *linebuf;
+   size_t bufsize = MAX_LENGTH;
+   int eolpos = 0;
+
+   if (feof(stream)) return *aLinePtr = 0;
+   if (!(linebuf = malloc(bufsize))) {
+      perror("fgetslong: malloc");
+      exit(1);
+   }
+   linebuf[0] = '\0';
+   while (fgets(linebuf + eolpos, MAX_LENGTH, stream)) {
+      eolpos += strlen(linebuf + eolpos);
+      if (linebuf[eolpos - 1] == '\n') return *aLinePtr = linebuf;
+      bufsize += MAX_LENGTH;
+      if (!(linebuf = realloc(linebuf, bufsize))) {
+         perror("fgetslong: realloc");
+         exit(1);
+      }
+   }
+   return *aLinePtr = linebuf[0] ? linebuf : 0;
+}
 
 int main(int argc, char *argv[])
 {
     char **myargv;
-    char aLine[MAX_LENGTH];
-#ifdef HAVE_CHROOT    
+    char *aLine;
     char *firstdir="";
-#endif
 #ifdef MUST_DISABLE_SIGFPE
     signal(SIGFPE,SIG_IGN);
 #endif
@@ -313,16 +364,21 @@ int main(int argc, char *argv[])
          struct rusage  myusage;
          struct timeval starttime;
          struct timeval currenttime;
-         struct timezone tz;
 
-           tz.tz_minuteswest =0;
-           tz.tz_dsttime=0;
-           gettimeofday(&starttime,&tz);
+         gettimeofday(&starttime, NULL);
 #endif
          RemoteMode=1;
-#ifdef HAVE_CHROOT
           if ((argc == 3) && strcmp("",argv[2])){
-             if (getuid()==0){
+
+             if (
+#ifdef HAVE_GETUID
+                getuid()
+#else
+                1
+#endif
+                == 0 ){
+
+#ifdef HAVE_CHROOT
                 chroot(argv[2]);
                 if (errno!=0){
                    fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
@@ -331,8 +387,12 @@ int main(int argc, char *argv[])
                 }
                 ChangeRoot=1;
                 firstdir="/";
-             }
-             else{
+#else
+                fprintf(stderr,"ERROR: change root is not supported by your OS "
+                         "or at least by this copy of rrdtool\n");
+                exit(1);
+#endif
+             } else {
                 firstdir=argv[2];
              }
           }
@@ -343,34 +403,28 @@ int main(int argc, char *argv[])
                 exit(errno);
              }
           }
-#else
-          fprintf(stderr,"ERROR: change root is not supported by your OS "
-                         "or at least by this copy of rrdtool\n");
-          exit(1);
-#endif
 
-           while (fgets(aLine, sizeof(aLine)-1, stdin)){
+           while (fgetslong(&aLine, stdin)){
                if ((argc = CountArgs(aLine)) == 0)  {
-                   fprintf(stderr,"ERROR: not enough arguments\n");                
+                   printf("ERROR: not enough arguments\n");
                }
                if ((myargv = (char **) malloc((argc+1) * 
                                               sizeof(char *))) == NULL)   {
                    perror("malloc");
-                   return -1;
+                   exit(1);
                }
                if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
-                   fprintf(stderr, "ERROR: creating arguments\n");
-                   return -1;
-               }
-
-               if (HandleInputLine(argc, myargv, stdout))
-                   return -1;
-               free(myargv);
+                   printf("ERROR: creating arguments\n");
+               } else {
+                   int ret = HandleInputLine(argc, myargv, stdout);
+                   free(myargv);
+                   if (ret == 0){
+                       
 
 #if HAVE_GETRUSAGE
-               getrusage(RUSAGE_SELF,&myusage);
-               gettimeofday(&currenttime,&tz);
-               printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
+                    getrusage(RUSAGE_SELF,&myusage);
+                    gettimeofday(&currenttime,NULL);
+                    printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
                       (double)myusage.ru_utime.tv_sec+
                       (double)myusage.ru_utime.tv_usec/1000000.0,
                       (double)myusage.ru_stime.tv_sec+
@@ -379,9 +433,13 @@ int main(int argc, char *argv[])
                       +(double)(currenttime.tv_usec-starttime.tv_usec)
                       /1000000.0);
 #else
-               printf("OK\n");
-#endif
+                     printf("OK\n");
+                   
+#endif          
+                 }
+               }
                fflush(stdout); /* this is important for pipes to work */
+                free(aLine);
            }
        }
     else if (argc == 2)
@@ -395,9 +453,7 @@ int main(int argc, char *argv[])
                exit(0);
        }
     else {
-        if(HandleInputLine(argc, argv, stderr)) {
-            return 1;
-        }
+        exit(HandleInputLine(argc, argv, stderr));
     }
     return 0;
 }
@@ -413,14 +469,17 @@ int HandleInputLine(int argc, char **argv, FILE* out)
 #if defined(HAVE_SYS_STAT_H)
     struct stat   st;
 #endif
-    optind=0; /* reset gnu getopt */
-    opterr=0; /* no error messages */
+    char* cwd; /* To hold current working dir on call to pwd */
+
+    /* Reset errno to 0 before we start.
+    */
+    errno = 0;
 
     if (RemoteMode){
        if (argc>1 && strcmp("quit", argv[1]) == 0){
           if (argc>2){
              printf("ERROR: invalid parameter count for quit\n");
-             return(0);
+             return(1);
           }
           exit(0);
        }
@@ -428,43 +487,59 @@ int HandleInputLine(int argc, char **argv, FILE* out)
        if (argc>1 && strcmp("cd", argv[1]) == 0){
           if (argc>3){
              printf("ERROR: invalid parameter count for cd\n");
-             return(0);
+             return(1);
           }
 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
           if (getuid()==0 && ! ChangeRoot){
              printf("ERROR: chdir security problem - rrdtool is running as "
-                    "root an no chroot!\n");
-             return(0); 
+                    "root but not chroot!\n");
+             return(1); 
           }
 #endif
           chdir(argv[2]);
           if (errno!=0){
              printf("ERROR: %s\n",rrd_strerror(errno));
+            return(1);
+          }
+          return(0);
+       }
+       if (argc>1 && strcmp("pwd", argv[1]) == 0){
+          if (argc>2){
+             printf("ERROR: invalid parameter count for pwd\n");
+             return(1);
+          }
+          cwd = getcwd(NULL, MAXPATH);
+          if(cwd == NULL) {
+             printf("ERROR: %s\n",rrd_strerror(errno));
+             return(1);
           }
+          printf("%s\n", cwd);
+          free(cwd);
           return(0);
        }
        if (argc>1 && strcmp("mkdir", argv[1]) == 0){
           if (argc>3){
              printf("ERROR: invalid parameter count for mkdir\n");
-             return(0);
+             return(1);
           }
 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
           if (getuid()==0 && ! ChangeRoot){
              printf("ERROR: mkdir security problem - rrdtool is running as "
-                    "root an no chroot!\n");
-             return(0); 
+                    "root but not chroot!\n");
+             return(1); 
           }
 #endif
           mkdir(argv[2],0777);
           if (errno!=0){
              printf("ERROR: %s\n",rrd_strerror(errno));
+             return(1);
           }
           return(0);
        }
        if (argc>1 && strcmp("ls", argv[1]) == 0){
           if (argc>2){
              printf("ERROR: invalid parameter count for ls\n");
-             return(0);
+             return(1);
           }
           if ((curdir=opendir("."))!=NULL){
              while((dent=readdir(curdir))!=NULL){
@@ -480,6 +555,7 @@ int HandleInputLine(int argc, char **argv, FILE* out)
                    }
                 }
              }
+            closedir(curdir);
           }
           else{
              printf("ERROR: %s\n",rrd_strerror(errno));
@@ -540,20 +616,42 @@ int HandleInputLine(int argc, char **argv, FILE* out)
        }
        free(data);
     }
-       
+
     else if (strcmp("--version", argv[1]) == 0 ||
             strcmp("version", argv[1]) == 0 || 
             strcmp("v", argv[1]) == 0 ||
             strcmp("-v", argv[1]) == 0  ||
             strcmp("-version", argv[1]) == 0  )
-        printf("RRDtool 1.1.x  Copyright (C) 1997-2004 by Tobias Oetiker <tobi@oetiker.ch>\n");
+        printf("RRDtool " PACKAGE_VERSION "  Copyright by Tobi Oetiker, 1997-2005 (%f)\n",
+               rrd_version());
     else if (strcmp("restore", argv[1]) == 0)
        rrd_restore(argc-1, &argv[1]);
     else if (strcmp("resize", argv[1]) == 0)
        rrd_resize(argc-1, &argv[1]);
     else if (strcmp("last", argv[1]) == 0)
         printf("%ld\n",rrd_last(argc-1, &argv[1]));
-    else if (strcmp("first", argv[1]) == 0)
+    else if (strcmp("lastupdate", argv[1]) == 0) {
+          time_t      last_update;
+           char        **ds_namv;
+           char        **last_ds;
+           unsigned long ds_cnt,
+                       i;
+          if (rrd_lastupdate(argc-1, &argv[1], &last_update,
+                       &ds_cnt, &ds_namv, &last_ds) == 0) {
+               for (i=0; i<ds_cnt; i++)
+                       printf(" %s", ds_namv[i]);
+               printf("\n\n");
+               printf("%10lu:", last_update);
+               for (i=0; i<ds_cnt; i++) {
+                       printf(" %s", last_ds[i]);
+                       free(last_ds[i]);
+                       free(ds_namv[i]);
+               }
+               printf("\n");
+               free(last_ds);
+               free(ds_namv);
+          }
+    } else if (strcmp("first", argv[1]) == 0)
         printf("%ld\n",rrd_first(argc-1, &argv[1]));
     else if (strcmp("update", argv[1]) == 0)
        rrd_update(argc-1, &argv[1]);
@@ -580,13 +678,22 @@ int HandleInputLine(int argc, char **argv, FILE* out)
            free (data);
        }
     } else if (strcmp("xport", argv[1]) == 0) {
-       int xxsize;
+        int xxsize;
        unsigned long int j = 0;
        time_t        start,end, ti;
        unsigned long step, col_cnt,row_cnt;
        rrd_value_t   *data,*ptr;
        char          **legend_v;
-       if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
+        int           enumds = 0;
+        int           i;
+        size_t       vtag_s = strlen(COL_DATA_TAG) + 10; 
+        char         *vtag = malloc(vtag_s); 
+       for ( i = 2; i < argc; i++){
+               if (strcmp("--enumds", argv[i]) == 0)
+                       enumds = 1;
+       }
+
+        if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
          row_cnt = (end-start)/step;
          ptr = data;
          printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
@@ -613,11 +720,16 @@ int HandleInputLine(int argc, char **argv, FILE* out)
            printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
            for (j = 0; j < col_cnt; j++) {
              rrd_value_t newval = DNAN;
+              if (enumds == 1)
+               snprintf(vtag,vtag_s,"%s%lu", COL_DATA_TAG, j);
+             else
+               snprintf(vtag,vtag_s,"%s",COL_DATA_TAG);
+              
              newval = *ptr;
              if(isnan(newval)){
-               printf("<%s>NaN</%s>", COL_DATA_TAG, COL_DATA_TAG);
+                printf("<%s>NaN</%s>", vtag,vtag);
              } else {
-               printf("<%s>%0.10e</%s>", COL_DATA_TAG, newval, COL_DATA_TAG);
+               printf("<%s>%0.10e</%s>", vtag, newval, vtag);
              };
              ptr++;
            }
@@ -627,6 +739,7 @@ int HandleInputLine(int argc, char **argv, FILE* out)
          printf("  </%s>\n", DATA_TAG);
          printf("</%s>\n", ROOT_TAG);
        }
+        free(vtag);
     }
     else if (strcmp("graph", argv[1]) == 0) {
        char **calcpr;
@@ -637,8 +750,15 @@ int HandleInputLine(int argc, char **argv, FILE* out)
        double ymin,ymax;
        int i;
        int tostdout = (strcmp(argv[2],"-") == 0);      
+       int imginfo = 0;
+       for (i=2;i<argc;i++){
+               if (strcmp(argv[i],"--imginfo") == 0 || strcmp(argv[i],"-f") == 0){
+                       imginfo = 1;
+                       break;
+               }
+       }
        if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) != -1 ) {
-           if (!tostdout) 
+           if (!tostdout && !imginfo
                printf ("%dx%d\n",xsize,ysize);
            if (calcpr) {
                for(i=0;calcpr[i];i++){
index 56b4568dbd787468410391b3298748a84fdc8cfd..6663c56e501ae2d6c3af021e063ecc58f6f207ea 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.0.33  Copyright Tobias Oetiker, 1997 - 2000
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_tool.h   Common Header File
  *****************************************************************************/
@@ -11,12 +11,10 @@ extern "C" {
 #ifndef _RRD_TOOL_H
 #define _RRD_TOOL_H
 
-#ifdef WIN32
-#include "../confignt/config.h"
-#else
 #ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "../rrd_config.h"
+#elif defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
+#include "../win32/config.h"
 #endif
 
 #ifdef MUST_DISABLE_SIGFPE
@@ -26,12 +24,11 @@ extern "C" {
 #ifdef MUST_DISABLE_FPMASK
 #include <floatingpoint.h>
 #endif
-    
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <string.h>
-#include <time.h>
 #include <ctype.h>
 
 #if HAVE_SYS_PARAM_H
@@ -74,16 +71,26 @@ extern "C" {
 # include <sys/stat.h>
 #endif
 
-
 #if HAVE_UNISTD_H
 # include <unistd.h>
 #endif
-#if HAVE_SYS_TIME_H
+
+#if TIME_WITH_SYS_TIME
 # include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
 #endif
+
 #if HAVE_SYS_TIMES_H
 # include <sys/times.h>
 #endif
+
+
 #if HAVE_SYS_RESOURCE_H
 # include <sys/resource.h>
 #if (defined(__svr4__) && defined(__sun__))
@@ -95,29 +102,29 @@ extern int getrusage(int, struct rusage *);
 
 #include "rrd.h"
 
-#ifndef WIN32
-
-/* unix-only includes */
-#ifndef isnan
-int isnan(double value);
-#endif
-
-#else
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
 
 /* Win32 only includes */
 
 #include <float.h>        /* for _isnan  */
-#define isnan _isnan
-#define finite _finite
-#define isinf(a) (_fpclass(a) == _FPCLASS_NINF || _fpclass(a) == _FPCLASS_PINF)
+#include <io.h>           /* for chdir   */
+
 struct tm* localtime_r(const time_t *timep, struct tm* result);
 char* ctime_r(const time_t *timep, char* result);
 struct tm* gmtime_r(const time_t *timep, struct tm* result);
 char *strtok_r(char *str, const char *sep, char **last);
+
+#else
+
+/* unix-only includes */
+#if !defined isnan && !defined HAVE_ISNAN
+int isnan(double value);
+#endif
+
 #endif
 
 /* local include files -- need to be after the system ones */
-#include "getopt.h"
+#include "rrd_getopt.h"
 #include "rrd_format.h"
 
 #ifndef max
@@ -151,6 +158,8 @@ typedef struct info_t {
 } info_t;
 
 info_t *rrd_info(int, char **);
+int rrd_lastupdate(int argc, char **argv, time_t *last_update,
+                unsigned long *ds_cnt, char ***ds_namv, char ***last_ds);
 info_t *rrd_update_v(int, char **);
 char * sprintf_alloc(char *, ...);
 info_t *info_push(info_t *, char *, enum info_type, infoval);
@@ -159,8 +168,8 @@ info_t *info_push(info_t *, char *, enum info_type, infoval);
 
 int PngSize(FILE *, long *, long *);
 
-int rrd_create_fn(char *file_name, rrd_t *rrd);
-int rrd_fetch_fn(char *filename, enum cf_en cf_idx,
+int rrd_create_fn(const char *file_name, rrd_t *rrd);
+int rrd_fetch_fn(const char *filename, enum cf_en cf_idx,
                 time_t *start,time_t *end,
                 unsigned long *step,
                 unsigned long *ds_cnt,
@@ -177,7 +186,7 @@ int readfile(const char *file, char **buffer, int skipfirst);
 #define RRD_READONLY    0
 #define RRD_READWRITE   1
 
-enum cf_en cf_conv(char *string);
+enum cf_en cf_conv(const char *string);
 enum dst_en dst_conv(char *string);
 long ds_match(rrd_t *rrd,char *ds_nam);
 double rrd_diff(char *a, char *b);
index 1b5515d9eb0b03313a753c8e8650f902934d1f50..8aa163080f9bb19752cc1bcf1309950292e4b4f2 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * change header parameters of an rrd
  *****************************************************************************
@@ -61,6 +61,7 @@ rrd_tune(int argc, char **argv)
     double              min;
     double              max;
     char                dst[DST_SIZE];
+    optind = 0; opterr = 0;  /* initialize getopt */
 
 
     if(rrd_open(argv[1],&rrd_file,&rrd, RRD_READWRITE)==-1){
@@ -289,7 +290,7 @@ rrd_tune(int argc, char **argv)
                   rrd.ds_def[i].par[DS_min_val].u_val,
                   rrd.ds_def[i].par[DS_max_val].u_val);
                } else {
-               char *buffer;
+               char *buffer = NULL;
                rpn_compact2str((rpn_cdefds_t *) &(rrd.ds_def[i].par[DS_cdef]),rrd.ds_def,&buffer);
                printf("DS[%s] typ: %s\tcdef: %s\n", rrd.ds_def[i].ds_nam,rrd.ds_def[i].dst,buffer);
            free(buffer);
index 9da2cace41a418328e040128ac199c57f75fb7a5..ed79a6a15b1856b2a153468a8c4b0036ff40a9c0 100644 (file)
@@ -1,98 +1,19 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2004
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
  * rrd_update.c  RRD Update Function
  *****************************************************************************
  * $Id$
- * $Log$
- * Revision 1.17  2004/05/26 22:11:12  oetiker
- * reduce compiler warnings. Many small fixes. -- Mike Slifcak <slif@bellsouth.net>
- *
- * Revision 1.16  2004/05/25 20:52:16  oetiker
- * fix spelling and syntax, especially in messages that are printed -- Mike Slifcak
- *
- * Revision 1.15  2004/05/25 20:51:49  oetiker
- * Update displayed copyright messages to be consistent. -- Mike Slifcak
- *
- * Revision 1.14  2003/11/11 19:46:21  oetiker
- * replaced time_value with rrd_time_value as MacOS X introduced a struct of that name in their standard headers
- *
- * Revision 1.13  2003/11/11 19:38:03  oetiker
- * rrd files should NOT change size ever ... bulk update code wa buggy.
- * -- David M. Grimes <dgrimes@navisite.com>
- *
- * Revision 1.12  2003/09/04 13:16:12  oetiker
- * should not assigne but compare ... grrrrr
- *
- * Revision 1.11  2003/09/02 21:58:35  oetiker
- * be pickier about what we accept in rrd_update. Complain if things do not work out
- *
- * Revision 1.10  2003/04/29 19:14:12  jake
- * Change updatev RRA return from index_number to cf_nam, pdp_cnt.
- * Also revert accidental addition of -I to aclocal MakeMakefile.
- *
- * Revision 1.9  2003/04/25 18:35:08  jake
- * Alternate update interface, updatev. Returns info about CDPs written to disk as result of update. Output format is similar to rrd_info, a hash of key-values.
- *
- * Revision 1.8  2003/03/31 21:22:12  oetiker
- * enables RRDtool updates with microsecond or in case of windows millisecond
- * precision. This is needed to reduce time measurement error when archive step
- * is small. (<30s) --  Sasha Mikheev <sasha@avalon-net.co.il>
- *
- * Revision 1.7  2003/02/13 07:05:27  oetiker
- * Find attached the patch I promised to send to you. Please note that there
- * are three new source files (src/rrd_is_thread_safe.h, src/rrd_thread_safe.c
- * and src/rrd_not_thread_safe.c) and the introduction of librrd_th. This
- * library is identical to librrd, but it contains support code for per-thread
- * global variables currently used for error information only. This is similar
- * to how errno per-thread variables are implemented.  librrd_th must be linked
- * alongside of libpthred
- *
- * There is also a new file "THREADS", holding some documentation.
- *
- * -- Peter Stamfest <peter@stamfest.at>
- *
- * Revision 1.6  2002/02/01 20:34:49  oetiker
- * fixed version number and date/time
- *
- * Revision 1.5  2001/05/09 05:31:01  oetiker
- * Bug fix: when update of multiple PDP/CDP RRAs coincided
- * with interpolation of multiple PDPs an incorrect value was
- * stored as the CDP. Especially evident for GAUGE data sources.
- * Minor changes to rrdcreate.pod. -- Jake Brutlag <jakeb@corp.webtv.net>
- *
- * Revision 1.4  2001/03/10 23:54:41  oetiker
- * Support for COMPUTE data sources (CDEF data sources). Removes the RPN
- * parser and calculator from rrd_graph and puts then in a new file,
- * rrd_rpncalc.c. Changes to core files rrd_create and rrd_update. Some
- * clean-up of aberrant behavior stuff, including a bug fix.
- * Documentation update (rrdcreate.pod, rrdupdate.pod). Change xml format.
- * -- Jake Brutlag <jakeb@corp.webtv.net>
- *
- * Revision 1.3  2001/03/04 13:01:55  oetiker
- * Aberrant Behavior Detection support. A brief overview added to rrdtool.pod.
- * Major updates to rrd_update.c, rrd_create.c. Minor update to other core files.
- * This is backwards compatible! But new files using the Aberrant stuff are not readable
- * by old rrdtool versions. See http://cricket.sourceforge.net/aberrant/rrd_hw.htm
- * -- Jake Brutlag <jakeb@corp.webtv.net>
- *
- * Revision 1.2  2001/03/04 11:14:25  oetiker
- * added at-style-time@value:value syntax to rrd_update
- * --  Dave Bodenstab <imdave@mcs.net>
- *
- * Revision 1.1.1.1  2001/02/25 22:25:06  oetiker
- * checkin
- *
  *****************************************************************************/
 
 #include "rrd_tool.h"
 #include <sys/types.h>
 #include <fcntl.h>
 #ifdef HAVE_MMAP
- #include <sys/mman.h>
+include <sys/mman.h>
 #endif
 
-#ifdef WIN32
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
  #include <sys/locking.h>
  #include <sys/stat.h>
  #include <io.h>
 #include "rrd_rpncalc.h"
 
 #include "rrd_is_thread_safe.h"
+#include "unused.h"
 
-#ifdef WIN32
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
 /*
  * WIN32 does not have gettimeofday    and struct timeval. This is a quick and dirty
  * replacement.
  */
 #include <sys/timeb.h>
 
+#ifndef __MINGW32__
 struct timeval {
        time_t tv_sec; /* seconds */
        long tv_usec;  /* microseconds */
 };
+#endif
 
 struct __timezone {
        int  tz_minuteswest; /* minutes W of Greenwich */
        int  tz_dsttime;     /* type of dst correction */
 };
 
-static gettimeofday(struct timeval *t, struct __timezone *tz) {
-       
-       struct timeb current_time;
+static int gettimeofday(struct timeval *t, struct __timezone *tz) {
+
+       struct _timeb current_time;
 
        _ftime(&current_time);
-       
+
        t->tv_sec  = current_time.time;
        t->tv_usec = current_time.millitm * 1000;
+
+       return 0;
 }
 
 #endif
@@ -148,7 +74,12 @@ int LockRRD(FILE *rrd_file);
 #ifdef HAVE_MMAP
 info_t *write_RRA_row (rrd_t *rrd, unsigned long rra_idx, 
                                        unsigned long *rra_current,
-                                       unsigned short CDP_scratch_idx, FILE *rrd_file,
+                                       unsigned short CDP_scratch_idx,
+#ifndef DEBUG
+FILE UNUSED(*rrd_file),
+#else
+FILE *rrd_file,
+#endif
                                        info_t *pcdp_summary, time_t *rra_time, void *rrd_mmaped_file);
 #else
 info_t *write_RRA_row (rrd_t *rrd, unsigned long rra_idx, 
@@ -156,38 +87,20 @@ info_t *write_RRA_row (rrd_t *rrd, unsigned long rra_idx,
                                        unsigned short CDP_scratch_idx, FILE *rrd_file,
                                        info_t *pcdp_summary, time_t *rra_time);
 #endif
-int rrd_update_r(char *filename, char *template, int argc, char **argv);
-int _rrd_update(char *filename, char *template, int argc, char **argv, 
+int rrd_update_r(const char *filename, const char *tmplt, int argc, const char **argv);
+int _rrd_update(const char *filename, const char *tmplt, int argc, const char **argv, 
                                        info_t*);
 
 #define IFDNAN(X,Y) (isnan(X) ? (Y) : (X));
 
 
-#ifdef STANDALONE
-int 
-main(int argc, char **argv){
-        rrd_update(argc,argv);
-        if (rrd_test_error()) {
-                printf("RRDtool 1.1.x  Copyright (C) 1997-2004 by Tobias Oetiker <tobi@oetiker.ch>\n\n"
-                        "Usage: rrdupdate filename\n"
-                        "\t\t\t[--template|-t ds-name:ds-name:...]\n"
-                        "\t\t\ttime|N:value[:value...]\n\n"
-                        "\t\t\tat-time@value[:value...]\n\n"
-                        "\t\t\t[ time:value[:value...] ..]\n\n");
-                                   
-                printf("ERROR: %s\n",rrd_get_error());
-                rrd_clear_error();                                                            
-                return 1;
-        }
-        return 0;
-}
-#endif
-
 info_t *rrd_update_v(int argc, char **argv)
 {
-    char             *template = NULL;          
+    char             *tmplt = NULL;          
        info_t *result = NULL;
        infoval rc;
+      rc.u_int = -1;
+    optind = 0; opterr = 0;  /* initialize getopt */
 
     while (1) {
                static struct option long_options[] =
@@ -205,12 +118,11 @@ info_t *rrd_update_v(int argc, char **argv)
                
                switch(opt) {
                case 't':
-                       template = optarg;
+                       tmplt = optarg;
                        break;
                
                case '?':
                        rrd_set_error("unknown option '%s'",argv[optind-1]);
-            rc.u_int = -1;
                        goto end_tag;
                }
     }
@@ -218,12 +130,12 @@ info_t *rrd_update_v(int argc, char **argv)
     /* need at least 2 arguments: filename, data. */
     if (argc-optind < 2) {
                rrd_set_error("Not enough arguments");
-        rc.u_int = -1;
                goto end_tag;
     }
+    rc.u_int = 0;
     result = info_push(NULL,sprintf_alloc("return_value"),RD_I_INT,rc);
-       rc.u_int = _rrd_update(argv[optind], template,
-                     argc - optind - 1, argv + optind + 1, result);
+       rc.u_int = _rrd_update(argv[optind], tmplt,
+                     argc - optind - 1, (const char **)(argv + optind + 1), result);
     result->value.u_int = rc.u_int;
 end_tag:
     return result;
@@ -232,8 +144,9 @@ end_tag:
 int
 rrd_update(int argc, char **argv)
 {
-    char             *template = NULL;          
+    char             *tmplt = NULL;          
     int rc;
+    optind = 0; opterr = 0;  /* initialize getopt */
 
     while (1) {
                static struct option long_options[] =
@@ -251,7 +164,7 @@ rrd_update(int argc, char **argv)
                
                switch(opt) {
                case 't':
-                       template = optarg;
+                       tmplt = optarg;
                        break;
                
                case '?':
@@ -267,19 +180,19 @@ rrd_update(int argc, char **argv)
                return -1;
     }
  
-       rc = rrd_update_r(argv[optind], template,
-                     argc - optind - 1, argv + optind + 1);
+       rc = rrd_update_r(argv[optind], tmplt,
+                     argc - optind - 1, (const char **)(argv + optind + 1));
     return rc;
 }
 
 int
-rrd_update_r(char *filename, char *template, int argc, char **argv)
+rrd_update_r(const char *filename, const char *tmplt, int argc, const char **argv)
 {
-   return _rrd_update(filename, template, argc, argv, NULL);
+   return _rrd_update(filename, tmplt, argc, argv, NULL);
 }
 
 int
-_rrd_update(char *filename, char *template, int argc, char **argv, 
+_rrd_update(const char *filename, const char *tmplt, int argc, const char **argv, 
    info_t *pcdp_summary)
 {
 
@@ -298,7 +211,7 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
                                          * spot in the rrd file. */
     unsigned long    rra_pos_tmp;        /* temporary byte pointer. */
     double           interval,
-       pre_int,post_int;                /* interval between this and
+                     pre_int,post_int;   /* interval between this and
                                          * the last run */
     unsigned long    proc_pdp_st;        /* which pdp_st was the last
                                          * to be processed */
@@ -318,14 +231,14 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
                                          * cdp values */
 
     long             *tmpl_idx;          /* index representing the settings
-                                           transported by the template index */
+                                           transported by the tmplt index */
     unsigned long    tmpl_cnt = 2;       /* time and data */
 
     FILE             *rrd_file;
     rrd_t            rrd;
-    time_t           current_time;
-       time_t           rra_time; /* time of update for a RRA */
-    unsigned long    current_time_usec;  /* microseconds part of current time */
+    time_t           current_time = 0;
+    time_t           rra_time = 0;      /* time of update for a RRA */
+    unsigned long    current_time_usec=0;/* microseconds part of current time */
     struct timeval   tmp_time;           /* used for time conversion */
 
     char             **updvals;
@@ -348,11 +261,13 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
     rpnstack_t       rpnstack; /* used for COMPUTE DS */
     int                     version;  /* rrd version */
     char             *endptr; /* used in the conversion */
+
 #ifdef HAVE_MMAP
     void            *rrd_mmaped_file;
     unsigned long    rrd_filesize;
 #endif
 
+
     rpnstack_init(&rpnstack);
 
     /* need at least 1 arguments: data. */
@@ -366,6 +281,7 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
     if(rrd_open(filename,&rrd_file,&rrd, RRD_READWRITE)==-1){
        return -1;
     }
+
     /* initialize time */
     version = atoi(rrd.stat_head->version);
     gettimeofday(&tmp_time, 0);
@@ -432,7 +348,7 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
         fclose(rrd_file);
        return(-1);
     }
-    /* initialize template redirector */
+    /* initialize tmplt redirector */
     /* default config example (assume DS 1 is a CDEF DS)
        tmpl_idx[0] -> 0; (time)
        tmpl_idx[1] -> 1; (DS 0)
@@ -446,17 +362,19 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
        }
     tmpl_cnt= ii;
 
-    if (template) {
+    if (tmplt) {
+       /* we should work on a writeable copy here */
        char *dsname;
        unsigned int tmpl_len;
-       dsname = template;
+       char *tmplt_copy = strdup(tmplt);
+       dsname = tmplt_copy;
        tmpl_cnt = 1; /* the first entry is the time */
-       tmpl_len = strlen(template);
+       tmpl_len = strlen(tmplt_copy);
        for(i=0;i<=tmpl_len ;i++) {
-           if (template[i] == ':' || template[i] == '\0') {
-               template[i] = '\0';
+           if (tmplt_copy[i] == ':' || tmplt_copy[i] == '\0') {
+               tmplt_copy[i] = '\0';
                if (tmpl_cnt>rrd.stat_head->ds_cnt){
-                   rrd_set_error("Template contains more DS definitions than RRD");
+                   rrd_set_error("tmplt contains more DS definitions than RRD");
                    free(updvals); free(pdp_temp);
                    free(tmpl_idx); rrd_free(&rrd);
                    fclose(rrd_file); return(-1);
@@ -464,21 +382,23 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
                if ((tmpl_idx[tmpl_cnt++] = ds_match(&rrd,dsname)) == -1){
                    rrd_set_error("unknown DS name '%s'",dsname);
                    free(updvals); free(pdp_temp);
+                   free(tmplt_copy);
                    free(tmpl_idx); rrd_free(&rrd);
                    fclose(rrd_file); return(-1);
                } else {
                  /* the first element is always the time */
                  tmpl_idx[tmpl_cnt-1]++; 
-                 /* go to the next entry on the template */
-                 dsname = &template[i+1];
+                 /* go to the next entry on the tmplt_copy */
+                 dsname = &tmplt_copy[i+1];
                   /* fix the damage we did before */
                   if (i<tmpl_len) {
-                     template[i]=':';
+                     tmplt_copy[i]=':';
                   } 
 
                }
            }       
        }
+       free(tmplt_copy);
     }
     if ((pdp_new = malloc(sizeof(rrd_value_t)
                          *rrd.stat_head->ds_cnt))==NULL){
@@ -507,10 +427,15 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
         fclose(rrd_file);
        return(-1);
     }
+#ifdef HAVE_MADVISE
+    /* when we use mmaping we tell the kernel the mmap equivalent
+       of POSIX_FADV_RANDOM */
+    madvise(rrd_mmaped_file,rrd_filesize,POSIX_MADV_RANDOM);
+#endif
 #endif
     /* loop through the arguments. */
     for(arg_i=0; arg_i<argc;arg_i++) {
-       char *stepper = malloc((strlen(argv[arg_i])+1)*sizeof(char));
+       char *stepper = strdup(argv[arg_i]);
         char *step_start = stepper;
        char *p;
        char *parsetime_error = NULL;
@@ -518,6 +443,7 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
        struct rrd_time_value ds_tv;
         if (stepper == NULL){
                 rrd_set_error("failed duplication argv entry");
+               free(step_start);
                 free(updvals);
                 free(pdp_temp);  
                 free(tmpl_idx);
@@ -531,7 +457,6 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
        /* initialize all ds input to unknown except the first one
            which has always got to be set */
        for(ii=1;ii<=rrd.stat_head->ds_cnt;ii++) updvals[ii] = "U";
-       strcpy(stepper,argv[arg_i]);
        updvals[0]=stepper;
        /* separate all ds elements; first must be examined separately
           due to alternate time syntax */
@@ -544,7 +469,7 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
            *p = '\0';
            stepper = p+1;
        } else {
-           rrd_set_error("expected timestamp not found in data source from %s:...",
+           rrd_set_error("expected timestamp not found in data source from %s",
                          argv[arg_i]);
            free(step_start);
            break;
@@ -563,7 +488,7 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
        }
 
        if (ii != tmpl_cnt-1) {
-           rrd_set_error("expected %lu data source readings (got %lu) from %s:...",
+           rrd_set_error("expected %lu data source readings (got %lu) from %s",
                          tmpl_cnt-1, ii, argv[arg_i]);
            free(step_start);
            break;
@@ -597,13 +522,15 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
            double tmp;
            tmp = strtod(updvals[0], 0);
            current_time = floor(tmp);
-           current_time_usec = (long)((tmp - current_time) * 1000000L);
+           current_time_usec = (long)((tmp-(double)current_time) * 1000000.0);
        }
        /* dont do any correction for old version RRDs */
        if(version < 3) 
            current_time_usec = 0;
        
-       if(current_time <= rrd.live_head->last_up){
+       if(current_time < rrd.live_head->last_up || 
+         (current_time == rrd.live_head->last_up && 
+          (long)current_time_usec <= (long)rrd.live_head->last_up_usec)) {
            rrd_set_error("illegal attempt to update using time %ld when "
                          "last update time is %ld (minimum one second step)",
                          current_time, rrd.live_head->last_up);
@@ -632,12 +559,14 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
        /* when did the last pdp_st occur */
        occu_pdp_age = current_time % rrd.stat_head->pdp_step;
        occu_pdp_st = current_time - occu_pdp_age;
+
        /* interval = current_time - rrd.live_head->last_up; */
-       interval    = current_time + ((double)current_time_usec - (double)rrd.live_head->last_up_usec)/1000000.0 - rrd.live_head->last_up;
-    
+       interval    = (double)(current_time - rrd.live_head->last_up) 
+                   + (double)((long)current_time_usec - (long)rrd.live_head->last_up_usec)/1000000.0;
+
        if (occu_pdp_st > proc_pdp_st){
            /* OK we passed the pdp_st moment*/
-           pre_int =  occu_pdp_st - rrd.live_head->last_up; /* how much of the input data
+           pre_int =  (long)occu_pdp_st - rrd.live_head->last_up; /* how much of the input data
                                                              * occurred before the latest
                                                              * pdp_st moment*/
            pre_int -= ((double)rrd.live_head->last_up_usec)/1000000.0; /* adjust usecs */
@@ -666,15 +595,23 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
        for(i=0;i<rrd.stat_head->ds_cnt;i++){
            enum dst_en dst_idx;
            dst_idx= dst_conv(rrd.ds_def[i].dst);
-               /* NOTE: DST_CDEF should never enter this if block, because
-                * updvals[i+1][0] is initialized to 'U'; unless the caller
-                * accidently specified a value for the DST_CDEF. To handle 
-                * this case, an extra check is required. */
+
+            /* make sure we do not build diffs with old last_ds values */
+           if(rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt < interval) {
+               strncpy(rrd.pdp_prep[i].last_ds,"U",LAST_DS_LEN-1);
+               rrd.pdp_prep[i].last_ds[LAST_DS_LEN-1]='\0';
+           }
+
+           /* NOTE: DST_CDEF should never enter this if block, because
+             * updvals[i+1][0] is initialized to 'U'; unless the caller
+            * accidently specified a value for the DST_CDEF. To handle 
+             * this case, an extra check is required. */
+
            if((updvals[i+1][0] != 'U') &&
                   (dst_idx != DST_CDEF) &&
               rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt >= interval) {
               double rate = DNAN;
-              /* the data source type defines how to process the data */
+              /* the data source type defines how to process the data */
                /* pdp_new contains rate * time ... eg the bytes
                 * transferred during the interval. Doing it this way saves
                 * a lot of math operations */
@@ -685,7 +622,7 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
                case DST_DERIVE:
                    if(rrd.pdp_prep[i].last_ds[0] != 'U'){
                       for(ii=0;updvals[i+1][ii] != '\0';ii++){
-                            if(updvals[i+1][ii] < '0' || updvals[i+1][ii] > '9' || (ii==0 && updvals[i+1][ii] == '-')){
+                            if((updvals[i+1][ii] < '0' || updvals[i+1][ii] > '9') && (ii != 0 && updvals[i+1][ii] != '-')){
                                  rrd_set_error("not a simple integer: '%s'",updvals[i+1]);
                                  break;
                             }
@@ -758,6 +695,7 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
                /* no news is news all the same */
                pdp_new[i] = DNAN;
            }
+
            
            /* make a copy of the command line argument for the next run */
 #ifdef DEBUG
@@ -770,11 +708,8 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
                    rrd.pdp_prep[i].last_ds,
                    updvals[i+1], pdp_new[i]);
 #endif
-           if(dst_idx == DST_COUNTER || dst_idx == DST_DERIVE){
-               strncpy(rrd.pdp_prep[i].last_ds,
-                       updvals[i+1],LAST_DS_LEN-1);
-               rrd.pdp_prep[i].last_ds[LAST_DS_LEN-1]='\0';
-           }
+           strncpy(rrd.pdp_prep[i].last_ds, updvals[i+1],LAST_DS_LEN-1);
+           rrd.pdp_prep[i].last_ds[LAST_DS_LEN-1]='\0';
        }
        /* break out of the argument parsing loop if the error_string is set */
        if (rrd_test_error()){
@@ -787,10 +722,18 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
            /* no we have not passed a pdp_st moment. therefore update is simple */
 
            for(i=0;i<rrd.stat_head->ds_cnt;i++){
-               if(isnan(pdp_new[i]))
-                   rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt += interval;
-               else
-                   rrd.pdp_prep[i].scratch[PDP_val].u_val+= pdp_new[i];
+               if(isnan(pdp_new[i])) {            
+                   /* this is not realy accurate if we use subsecond data arival time
+                      should have thought of it when going subsecond resolution ...
+                       sorry next format change we will have it! */
+                   rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt += floor(interval);          
+               } else {
+                    if (isnan( rrd.pdp_prep[i].scratch[PDP_val].u_val )){
+                       rrd.pdp_prep[i].scratch[PDP_val].u_val= pdp_new[i];
+                    } else {
+                       rrd.pdp_prep[i].scratch[PDP_val].u_val+= pdp_new[i];
+                    }
+               }
 #ifdef DEBUG
                fprintf(stderr,
                        "NO PDP  ds[%lu]\t"
@@ -810,24 +753,38 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
            pdp_temp[] will contain the rate for cdp */
 
            for(i=0;i<rrd.stat_head->ds_cnt;i++){
-               /* update pdp_prep to the current pdp_st */
+               /* update pdp_prep to the current pdp_st. */
+                double pre_unknown = 0.0;              
                if(isnan(pdp_new[i]))
-                   rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt += pre_int;
-               else
-                   rrd.pdp_prep[i].scratch[PDP_val].u_val += 
-                       pdp_new[i]/(double)interval*(double)pre_int;
+                    /* a final bit of unkonwn to be added bevore calculation
+                    * we use a tempaorary variable for this so that we 
+                    * don't have to turn integer lines before using the value */                
+                   pre_unknown = pre_int;
+               else {
+                    if (isnan( rrd.pdp_prep[i].scratch[PDP_val].u_val )){
+                       rrd.pdp_prep[i].scratch[PDP_val].u_val=         pdp_new[i]/interval*pre_int;
+                    } else {
+                       rrd.pdp_prep[i].scratch[PDP_val].u_val+= pdp_new[i]/interval*pre_int;
+                    }
+                }
+               
 
                /* if too much of the pdp_prep is unknown we dump it */
-               if ((rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt 
-                    > rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt) ||
+               if ( 
+                   /* removed because this does not agree with the definition
+                      a heart beat can be unknown */
+                   /* (rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt 
+                    > rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt) || */
+                   /* if the interval is larger thatn mrhb we get NAN */
+                   (interval > rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt) ||
                    (occu_pdp_st-proc_pdp_st <= 
                     rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt)) {
                    pdp_temp[i] = DNAN;
                } else {
                    pdp_temp[i] = rrd.pdp_prep[i].scratch[PDP_val].u_val
-                       / (double)( occu_pdp_st
-                                  - proc_pdp_st
-                                  - rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt);
+                       / ((double)(occu_pdp_st - proc_pdp_st
+                                    - rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt)
+                            -pre_unknown);
                }
 
                /* process CDEF data sources; remember each CDEF DS can
@@ -852,12 +809,15 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
         
                /* make pdp_prep ready for the next run */
                if(isnan(pdp_new[i])){
-                   rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt = post_int;
-                   rrd.pdp_prep[i].scratch[PDP_val].u_val = 0.0;
+                   /* this is not realy accurate if we use subsecond data arival time
+                      should have thought of it when going subsecond resolution ...
+                       sorry next format change we will have it! */
+                   rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt = floor(post_int);
+                   rrd.pdp_prep[i].scratch[PDP_val].u_val = DNAN;
                } else {
                    rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt = 0;
                    rrd.pdp_prep[i].scratch[PDP_val].u_val = 
-                       pdp_new[i]/(double)interval*(double)post_int;
+                       pdp_new[i]/interval*post_int;
                }
 
 #ifdef DEBUG
@@ -1240,7 +1200,7 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
                i < rrd.stat_head->rra_cnt;
            rra_start += rrd.rra_def[i].row_cnt * rrd.stat_head -> ds_cnt * sizeof(rrd_value_t),
                i++) {
-               /* is there anything to write for this RRA? If not, continue. */
+               /* is th5Aere anything to write for this RRA? If not, continue. */
         if (rra_step_cnt[i] == 0) continue;
 
                /* write the first row */
@@ -1443,6 +1403,20 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
        fclose(rrd_file);
        return(-1);
     }
+    
+#ifdef HAVE_POSIX_FADVISExxx
+
+    /* with update we have write ops, so they will probably not be done by now, this means
+       the buffers will not get freed. But calling this for the whole file - header
+       will let the data off the hook as soon as it is written when if it is from a previous
+       update cycle. Calling fdsync to force things is much too hard here. */
+
+    if (0 != posix_fadvise(fileno(rrd_file), rra_begin, 0, POSIX_FADV_DONTNEED)) {
+         rrd_set_error("setting POSIX_FADV_DONTNEED on '%s': %s",filename, rrd_strerror(errno));
+         fclose(rrd_file);
+         return(-1);
+    } 
+#endif
 
     /* OK now close the files and free the memory */
     if(fclose(rrd_file) != 0){
@@ -1462,11 +1436,9 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
         * critical except during the burning cycles. */
        if (schedule_smooth)
        {
-#ifndef WIN32
-         rrd_file = fopen(filename,"r+");
-#else
          rrd_file = fopen(filename,"rb+");
-#endif
+          
+
          rra_start = rra_begin;
          for (i = 0; i < rrd.stat_head -> rra_cnt; ++i)
          {
@@ -1483,6 +1455,14 @@ _rrd_update(char *filename, char *template, int argc, char **argv,
            rra_start += rrd.rra_def[i].row_cnt
              *rrd.stat_head->ds_cnt*sizeof(rrd_value_t);
          }
+#ifdef HAVE_POSIX_FADVISExxx
+          /* same procedure as above ... */
+          if (0 != posix_fadvise(fileno(rrd_file), rra_begin, 0, POSIX_FADV_DONTNEED)) {
+             rrd_set_error("setting POSIX_FADV_DONTNEED on '%s': %s",filename, rrd_strerror(errno));
+             fclose(rrd_file);
+             return(-1);
+          } 
+#endif
          fclose(rrd_file);
        }
     rrd_free(&rrd);
@@ -1508,15 +1488,7 @@ LockRRD(FILE *rrdfile)
     rrd_fd = fileno(rrdfile);
 
        {
-#ifndef WIN32    
-    struct flock       lock;
-    lock.l_type = F_WRLCK;    /* exclusive write lock */
-    lock.l_len = 0;          /* whole file */
-    lock.l_start = 0;        /* start of file */
-    lock.l_whence = SEEK_SET;   /* end of file */
-
-    rcstat = fcntl(rrd_fd, F_SETLK, &lock);
-#else
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
     struct _stat st;
 
     if ( _fstat( rrd_fd, &st ) == 0 ) {
@@ -1524,6 +1496,14 @@ LockRRD(FILE *rrdfile)
     } else {
            rcstat = -1;
     }
+#else
+    struct flock       lock;
+    lock.l_type = F_WRLCK;    /* exclusive write lock */
+    lock.l_len = 0;          /* whole file */
+    lock.l_start = 0;        /* start of file */
+    lock.l_whence = SEEK_SET;   /* end of file */
+
+    rcstat = fcntl(rrd_fd, F_SETLK, &lock);
 #endif
        }
 
@@ -1534,7 +1514,12 @@ LockRRD(FILE *rrdfile)
 #ifdef HAVE_MMAP
 info_t
 *write_RRA_row (rrd_t *rrd, unsigned long rra_idx, unsigned long *rra_current,
-              unsigned short CDP_scratch_idx, FILE *rrd_file,
+              unsigned short CDP_scratch_idx, 
+#ifndef DEBUG
+FILE UNUSED(*rrd_file),
+#else
+FILE *rrd_file,
+#endif
                   info_t *pcdp_summary, time_t *rra_time, void *rrd_mmaped_file)
 #else
 info_t
diff --git a/src/rrd_version.c b/src/rrd_version.c
new file mode 100644 (file)
index 0000000..7d13aeb
--- /dev/null
@@ -0,0 +1,23 @@
+/*****************************************************************************
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
+ *****************************************************************************
+ * rrd_version Return
+ *****************************************************************************
+ * Initial version by Burton Strauss, ntopSupport.com - 5/2005
+ *****************************************************************************/
+
+#include "rrd_tool.h"
+
+double
+rrd_version(void)
+{
+  return NUMVERS;
+}
+
+char *
+rrd_strversion(void)
+{
+  return PACKAGE_VERSION;
+}
+
+
index 3ba1b521c75e41f2efaef5ddf3b17b26a4b8b290..ef964a039ad24eb3733480549d48110621658980 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * RRDtool 1.0.37  Copyright Tobias Oetiker, 1997 - 2000
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  ****************************************************************************
  * rrd_xport.c  export RRD data 
  ****************************************************************************/
@@ -9,8 +9,9 @@
 #include "rrd_tool.h"
 #include "rrd_graph.h"
 #include "rrd_xport.h"
+#include "unused.h"
 
-#ifdef WIN32
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
 #include <io.h>
 #include <fcntl.h>
 #endif
@@ -30,7 +31,7 @@ int rrd_xport_fn(image_desc_t *,
 
 
 int 
-rrd_xport(int argc, char **argv, int *xsize,
+rrd_xport(int argc, char **argv, int UNUSED(*xsize),
          time_t         *start,
          time_t         *end,        /* which time frame do you want ?
                                       * will be changed to represent reality */
@@ -46,6 +47,7 @@ rrd_xport(int argc, char **argv, int *xsize,
     time_t        start_tmp=0,end_tmp=0;
     struct rrd_time_value start_tv, end_tv;
     char           *parsetime_error = NULL;
+    optind = 0; opterr = 0;  /* initialize getopt */
 
     rrd_graph_init(&im);
 
@@ -59,6 +61,7 @@ rrd_xport(int argc, char **argv, int *xsize,
            {"end",        required_argument, 0,  'e'},
            {"maxrows",    required_argument, 0,  'm'},
            {"step",       required_argument, 0,   261},
+           {"enumds",     no_argument,       0,   262}, /* these are handled in the frontend ... */
            {0,0,0,0}
        };
        int option_index = 0;
@@ -74,6 +77,8 @@ rrd_xport(int argc, char **argv, int *xsize,
        case 261:
            im.step =  atoi(optarg);
            break;
+       case 262:
+           break;
        case 's':
            if ((parsetime_error = parsetime(optarg, &start_tv))) {
                rrd_set_error( "start time: %s", parsetime_error );
@@ -94,7 +99,7 @@ rrd_xport(int argc, char **argv, int *xsize,
            }
            break;
        case '?':
-           rrd_set_error("unknown option '%c'", optopt);
+            rrd_set_error("unknown option '%s'",argv[optind-1]);
             return -1;
        }
     }
index d8d76d4478730173e557285ebbf5a5fc780343ce..f8dd93e0648a4ebfa147f67dd7bd4d43cc6a46df 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * RRDtool 1.0.37  Copyright Tobias Oetiker, 1997 - 2000
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  ****************************************************************************
  * rrd_xport.h  contains XML related constants
  ****************************************************************************/
diff --git a/src/rrdtool.dsp b/src/rrdtool.dsp
deleted file mode 100644 (file)
index 215ac7d..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-# Microsoft Developer Studio Project File - Name="rrdtool" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Console Application" 0x0103
-
-CFG=rrdtool - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE 
-!MESSAGE NMAKE /f "rrdtool.mak".
-!MESSAGE 
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE 
-!MESSAGE NMAKE /f "rrdtool.mak" CFG="rrdtool - Win32 Debug"
-!MESSAGE 
-!MESSAGE Possible choices for configuration are:
-!MESSAGE 
-!MESSAGE "rrdtool - Win32 Release" (based on "Win32 (x86) Console Application")
-!MESSAGE "rrdtool - Win32 Debug" (based on "Win32 (x86) Console Application")
-!MESSAGE 
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF  "$(CFG)" == "rrdtool - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "rrdtool_"
-# PROP BASE Intermediate_Dir "rrdtool_"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "toolrelease"
-# PROP Intermediate_Dir "toolrelease"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /MD /W3 /GX /I "\Program Files\GnuWin32\include" /I "\Program Files\GnuWin32\include\freetype2" /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /D "_CTYPE_DISABLE_MACROS" /D MAKE_TIMESTAMP=\"WIN32\" /FD /c
-# SUBTRACT CPP /YX
-# ADD BASE RSC /l 0x100c /d "NDEBUG"
-# ADD RSC /l 0x100c /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
-# ADD LINK32 libpng.lib libz.lib libart_lgpl.lib libfreetype.lib kernel32.lib user32.lib /nologo /subsystem:console /incremental:yes /debug /machine:I386 /libpath:"\Program Files\GnuWin32\lib"
-
-!ELSEIF  "$(CFG)" == "rrdtool - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "rrdtool0"
-# PROP BASE Intermediate_Dir "rrdtool0"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "tooldebug"
-# PROP Intermediate_Dir "tooldebug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /MD /W3 /Gm /GX /ZI /Od /I "\Program Files\GnuWin32\include\freetype2" /I "\Program Files\GnuWin32\include" /D "_DEBUG" /D "_CONSOLE" /D "WIN32" /D "_MBCS" /D "_CTYPE_DISABLE_MACROS" /D MAKE_TIMESTAMP=\"WIN32\" /FR /FD /c
-# SUBTRACT CPP /YX
-# ADD BASE RSC /l 0x100c /d "_DEBUG"
-# ADD RSC /l 0x100c /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo /o"rrdtool.bsc"
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 libpng.lib libz.lib libart_lgpl.lib libfreetype.lib kernel32.lib user32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"\Program Files\GnuWin32\lib"
-
-!ENDIF 
-
-# Begin Target
-
-# Name "rrdtool - Win32 Release"
-# Name "rrdtool - Win32 Debug"
-# Begin Source File
-
-SOURCE=.\rrd_tool.c
-# End Source File
-# End Target
-# End Project
diff --git a/src/rrdtool.dsw b/src/rrdtool.dsw
deleted file mode 100644 (file)
index 49f1673..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-Microsoft Developer Studio Workspace File, Format Version 6.00
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
-
-###############################################################################
-
-Project: "rrd"=".\rrd.dsp" - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Project: "rrdtool"=".\rrdtool.dsp" - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-    Begin Project Dependency
-    Project_Dep_Name rrd
-    End Project Dependency
-}}}
-
-###############################################################################
-
-Global:
-
-Package=<5>
-{{{
-}}}
-
-Package=<3>
-{{{
-}}}
-
-###############################################################################
-
diff --git a/src/rrdtool.sln b/src/rrdtool.sln
deleted file mode 100644 (file)
index 3aaa738..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-Microsoft Visual Studio Solution File, Format Version 8.00
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rrd", "rrd.vcproj", "{8DF24CAC-DF33-4131-8584-529054E341B3}"
-       ProjectSection(ProjectDependencies) = postProject
-       EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rrdtool", "rrdtool.vcproj", "{3A5A6297-3F61-498A-BA72-66D36144901B}"
-       ProjectSection(ProjectDependencies) = postProject
-               {8DF24CAC-DF33-4131-8584-529054E341B3} = {8DF24CAC-DF33-4131-8584-529054E341B3}
-       EndProjectSection
-EndProject
-Global
-       GlobalSection(SolutionConfiguration) = preSolution
-               Debug = Debug
-               Release = Release
-       EndGlobalSection
-       GlobalSection(ProjectConfiguration) = postSolution
-               {8DF24CAC-DF33-4131-8584-529054E341B3}.Debug.ActiveCfg = Debug|Win32
-               {8DF24CAC-DF33-4131-8584-529054E341B3}.Debug.Build.0 = Debug|Win32
-               {8DF24CAC-DF33-4131-8584-529054E341B3}.Release.ActiveCfg = Release|Win32
-               {8DF24CAC-DF33-4131-8584-529054E341B3}.Release.Build.0 = Release|Win32
-               {3A5A6297-3F61-498A-BA72-66D36144901B}.Debug.ActiveCfg = Debug|Win32
-               {3A5A6297-3F61-498A-BA72-66D36144901B}.Debug.Build.0 = Debug|Win32
-               {3A5A6297-3F61-498A-BA72-66D36144901B}.Release.ActiveCfg = Release|Win32
-               {3A5A6297-3F61-498A-BA72-66D36144901B}.Release.Build.0 = Release|Win32
-       EndGlobalSection
-       GlobalSection(ExtensibilityGlobals) = postSolution
-       EndGlobalSection
-       GlobalSection(ExtensibilityAddIns) = postSolution
-       EndGlobalSection
-EndGlobal
diff --git a/src/rrdtool.vcproj b/src/rrdtool.vcproj
deleted file mode 100644 (file)
index dad37e7..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
-       ProjectType="Visual C++"
-       Version="7.10"
-       Name="rrdtool"
-       SccProjectName=""
-       SccLocalPath="">
-       <Platforms>
-               <Platform
-                       Name="Win32"/>
-       </Platforms>
-       <Configurations>
-               <Configuration
-                       Name="Release|Win32"
-                       OutputDirectory=".\toolrelease"
-                       IntermediateDirectory=".\toolrelease"
-                       ConfigurationType="1"
-                       UseOfMFC="0"
-                       ATLMinimizesCRunTimeLibraryUsage="FALSE"
-                       CharacterSet="2">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="4"
-                               AdditionalIncludeDirectories="\Program Files\GnuWin32\include,\Program Files\GnuWin32\include\freetype2"
-                               PreprocessorDefinitions="NDEBUG;_WINDOWS;WIN32;_CTYPE_DISABLE_MACROS;MAKE_TIMESTAMP=\&quot;WIN32\&quot;"
-                               RuntimeLibrary="2"
-                               PrecompiledHeaderFile=".\toolrelease/rrdtool.pch"
-                               AssemblerListingLocation=".\toolrelease/"
-                               ObjectFile=".\toolrelease/"
-                               ProgramDataBaseFileName=".\toolrelease/"
-                               WarningLevel="3"
-                               SuppressStartupBanner="TRUE"
-                               CompileAs="0"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalDependencies="libpng.lib libz.lib libart_lgpl.lib libfreetype.lib"
-                               OutputFile=".\toolrelease/rrdtool.exe"
-                               LinkIncremental="1"
-                               SuppressStartupBanner="TRUE"
-                               AdditionalLibraryDirectories="\Program Files\GnuWin32\lib"
-                               GenerateDebugInformation="TRUE"
-                               ProgramDatabaseFile=".\toolrelease/rrdtool.pdb"
-                               SubSystem="1"
-                               TargetMachine="1"/>
-                       <Tool
-                               Name="VCMIDLTool"
-                               TypeLibraryName=".\toolrelease/rrdtool.tlb"
-                               HeaderFileName=""/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"
-                               PreprocessorDefinitions="NDEBUG"
-                               Culture="4108"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCXMLDataGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-                       <Tool
-                               Name="VCManagedWrapperGeneratorTool"/>
-                       <Tool
-                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
-               </Configuration>
-               <Configuration
-                       Name="Debug|Win32"
-                       OutputDirectory=".\tooldebug"
-                       IntermediateDirectory=".\tooldebug"
-                       ConfigurationType="1"
-                       UseOfMFC="0"
-                       ATLMinimizesCRunTimeLibraryUsage="FALSE"
-                       CharacterSet="2">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="0"
-                               AdditionalIncludeDirectories="\Program Files\GnuWin32\include\freetype2,\Program Files\GnuWin32\include"
-                               PreprocessorDefinitions="_DEBUG;_CONSOLE;WIN32;_CTYPE_DISABLE_MACROS;MAKE_TIMESTAMP=\&quot;WIN32\&quot;"
-                               RuntimeLibrary="2"
-                               PrecompiledHeaderFile=".\tooldebug/rrdtool.pch"
-                               AssemblerListingLocation=".\tooldebug/"
-                               ObjectFile=".\tooldebug/"
-                               ProgramDataBaseFileName=".\tooldebug/"
-                               BrowseInformation="1"
-                               WarningLevel="3"
-                               SuppressStartupBanner="TRUE"
-                               DebugInformationFormat="4"
-                               CompileAs="0"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalDependencies="libpng.lib libz.lib libart_lgpl.lib libfreetype.lib"
-                               OutputFile=".\tooldebug/rrdtool.exe"
-                               LinkIncremental="1"
-                               SuppressStartupBanner="TRUE"
-                               AdditionalLibraryDirectories="\Program Files\GnuWin32\lib"
-                               GenerateDebugInformation="TRUE"
-                               ProgramDatabaseFile=".\tooldebug/rrdtool.pdb"
-                               SubSystem="1"
-                               TargetMachine="1"/>
-                       <Tool
-                               Name="VCMIDLTool"
-                               TypeLibraryName=".\tooldebug/rrdtool.tlb"
-                               HeaderFileName=""/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"
-                               PreprocessorDefinitions="_DEBUG"
-                               Culture="4108"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCXMLDataGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-                       <Tool
-                               Name="VCManagedWrapperGeneratorTool"/>
-                       <Tool
-                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
-               </Configuration>
-       </Configurations>
-       <References>
-       </References>
-       <Files>
-               <File
-                       RelativePath="rrd_tool.c">
-                       <FileConfiguration
-                               Name="Release|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""/>
-                       </FileConfiguration>
-                       <FileConfiguration
-                               Name="Debug|Win32">
-                               <Tool
-                                       Name="VCCLCompilerTool"
-                                       Optimization="0"
-                                       AdditionalIncludeDirectories=""
-                                       PreprocessorDefinitions=""
-                                       BrowseInformation="1"/>
-                       </FileConfiguration>
-               </File>
-       </Files>
-       <Globals>
-       </Globals>
-</VisualStudioProject>
index cbc99a6d48dc99447cbaffb17be152134d0115fa..257f2c72531b3031564192c4b8e9dd3e5bc4617d 100644 (file)
@@ -1,51 +1,26 @@
 /*****************************************************************************
- * RRDtool 1.0.33  Copyright Tobias Oetiker, 1997 - 2000
+ * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
  *****************************************************************************
- * rrd_update.c  RRD Update Function
+ * rrdupdate.c  Main program for the (standalone) rrdupdate utility
  *****************************************************************************
  * $Id$
- * $Log$
- * Revision 1.3  2001/03/04 13:01:56  oetiker
- * Aberrant Behavior Detection support. A brief overview added to rrdtool.pod.
- * Major updates to rrd_update.c, rrd_create.c. Minor update to other core files.
- * This is backwards compatible! But new files using the Aberrant stuff are not readable
- * by old rrdtool versions. See http://cricket.sourceforge.net/aberrant/rrd_hw.htm
- * -- Jake Brutlag <jakeb@corp.webtv.net>
- *
- * Revision 1.2  2001/03/04 11:14:25  oetiker
- * added at-style-time@value:value syntax to rrd_update
- * --  Dave Bodenstab <imdave@mcs.net>
- * Revision 1.1  2001/02/25 22:25:06  oetiker
- * Initial revision
- *
  *****************************************************************************/
 
-#include "rrd_tool.h"
-#include <sys/types.h>
-#include <fcntl.h>
-
-#ifdef WIN32
- #include <sys/locking.h>
- #include <sys/stat.h>
- #include <io.h>
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__) && !defined(HAVE_CONFIG_H)
+#include "../win32/config.h"
+#else
+#ifdef HAVE_CONFIG_H
+#include "../rrd_config.h"
+#endif
 #endif
 
-/* Prototypes */
-int LockRRD(FILE *rrd_file);
-void write_RRA_row (rrd_t *rrd, unsigned long rra_idx, unsigned long *rra_current,
-    unsigned short CDP_scratch_idx, FILE *rrd_file);
-/*#define DEBUG */
-
-#define IFDNAN(X,Y) (isnan(X) ? (Y) : (X));
-
+#include "rrd.h"
 
-#ifdef STANDALONE
 int 
 main(int argc, char **argv){
         rrd_update(argc,argv);
         if (rrd_test_error()) {
-                printf("RRDtool 1.0.33  Copyright 1997-2000 by Tobias Oetiker <tobi@oetiker.ch>\n\n"
+                printf("RRDtool " PACKAGE_VERSION "  Copyright by Tobi Oetiker, 1997-2007\n\n"
                         "Usage: rrdupdate filename\n"
                         "\t\t\t[--template|-t ds-name:ds-name:...]\n"
                         "\t\t\ttime|N:value[:value...]\n\n"
@@ -58,1127 +33,3 @@ main(int argc, char **argv){
         }
         return 0;
 }
-#endif
-
-int
-rrd_update(int argc, char **argv)
-{
-
-    int              arg_i = 2;
-    short            j;
-    long             i,ii,iii=1;
-
-    unsigned long    rra_begin;          /* byte pointer to the rra
-                                         * area in the rrd file.  this
-                                         * pointer never changes value */
-    unsigned long    rra_start;          /* byte pointer to the rra
-                                         * area in the rrd file.  this
-                                         * pointer changes as each rrd is
-                                         * processed. */
-    unsigned long    rra_current;        /* byte pointer to the current write
-                                         * spot in the rrd file. */
-    unsigned long    rra_pos_tmp;        /* temporary byte pointer. */
-    unsigned long    interval,
-       pre_int,post_int;                /* interval between this and
-                                         * the last run */
-    unsigned long    proc_pdp_st;        /* which pdp_st was the last
-                                         * to be processed */
-    unsigned long    occu_pdp_st;        /* when was the pdp_st
-                                         * before the last update
-                                         * time */
-    unsigned long    proc_pdp_age;       /* how old was the data in
-                                         * the pdp prep area when it
-                                         * was last updated */
-    unsigned long    occu_pdp_age;       /* how long ago was the last
-                                         * pdp_step time */
-    rrd_value_t      *pdp_new;           /* prepare the incoming data
-                                         * to be added the the
-                                         * existing entry */
-    rrd_value_t      *pdp_temp;          /* prepare the pdp values 
-                                         * to be added the the
-                                         * cdp values */
-
-    long             *tmpl_idx;          /* index representing the settings
-                                           transported by the template index */
-    long             tmpl_cnt = 2;       /* time and data */
-
-    FILE             *rrd_file;
-    rrd_t            rrd;
-    time_t           current_time = time(NULL);
-    char             **updvals;
-    int              schedule_smooth = 0;
-    char             *template = NULL;   
-       rrd_value_t      *seasonal_coef = NULL, *last_seasonal_coef = NULL;
-                                        /* a vector of future Holt-Winters seasonal coefs */
-    unsigned long    elapsed_pdp_st;
-                                        /* number of elapsed PDP steps since last update */
-    unsigned long    *rra_step_cnt = NULL;
-                                        /* number of rows to be updated in an RRA for a data
-                                         * value. */
-    unsigned long    start_pdp_offset;
-                                        /* number of PDP steps since the last update that
-                                         * are assigned to the first CDP to be generated
-                                         * since the last update. */
-    unsigned short   scratch_idx;
-                                        /* index into the CDP scratch array */
-    enum cf_en       current_cf;
-                                        /* numeric id of the current consolidation function */
-
-    while (1) {
-       static struct option long_options[] =
-       {
-           {"template",      required_argument, 0, 't'},
-           {0,0,0,0}
-       };
-       int option_index = 0;
-       int opt;
-       opt = getopt_long(argc, argv, "t:", 
-                         long_options, &option_index);
-       
-       if (opt == EOF)
-         break;
-       
-       switch(opt) {
-       case 't':
-           template = optarg;
-           break;
-
-       case '?':
-           rrd_set_error("unknown option '%s'",argv[optind-1]);
-            rrd_free(&rrd);            
-           return(-1);
-       }
-    }
-
-    /* need at least 2 arguments: filename, data. */
-    if (argc-optind < 2) {
-       rrd_set_error("Not enough arguments");
-       return -1;
-    }
-
-    if(rrd_open(argv[optind],&rrd_file,&rrd, RRD_READWRITE)==-1){
-       return -1;
-    }
-    rra_current = rra_start = rra_begin = ftell(rrd_file);
-    /* This is defined in the ANSI C standard, section 7.9.5.3:
-
-        When a file is opened with udpate mode ('+' as the second
-        or third character in the ... list of mode argument
-        variables), both input and ouptut may be performed on the
-        associated stream.  However, ...  input may not be directly
-        followed by output without an intervening call to a file
-        positioning function, unless the input oepration encounters
-        end-of-file. */
-    fseek(rrd_file, 0, SEEK_CUR);
-
-    
-    /* get exclusive lock to whole file.
-     * lock gets removed when we close the file.
-     */
-    if (LockRRD(rrd_file) != 0) {
-      rrd_set_error("could not lock RRD");
-      rrd_free(&rrd);
-      fclose(rrd_file);
-      return(-1);   
-    } 
-
-    if((updvals = malloc( sizeof(char*) * (rrd.stat_head->ds_cnt+1)))==NULL){
-       rrd_set_error("allocating updvals pointer array");
-       rrd_free(&rrd);
-        fclose(rrd_file);
-       return(-1);
-    }
-
-    if ((pdp_temp = malloc(sizeof(rrd_value_t)
-                          *rrd.stat_head->ds_cnt))==NULL){
-       rrd_set_error("allocating pdp_temp ...");
-       free(updvals);
-       rrd_free(&rrd);
-        fclose(rrd_file);
-       return(-1);
-    }
-
-    if ((tmpl_idx = malloc(sizeof(unsigned long)
-                          *(rrd.stat_head->ds_cnt+1)))==NULL){
-       rrd_set_error("allocating tmpl_idx ...");
-       free(pdp_temp);
-       free(updvals);
-       rrd_free(&rrd);
-        fclose(rrd_file);
-       return(-1);
-    }
-    /* initialize template redirector */
-    /* default config
-       tmpl_idx[0] -> 0; (time)
-       tmpl_idx[1] -> 1; (DS 0)
-       tmpl_idx[2] -> 2; (DS 1)
-       tmpl_idx[3] -> 3; (DS 2)
-       ... */
-    for (i=0;i<=rrd.stat_head->ds_cnt;i++) tmpl_idx[i]=i;
-    tmpl_cnt=rrd.stat_head->ds_cnt+1;
-    if (template) {
-       char *dsname;
-       int tmpl_len;
-       dsname = template;
-       tmpl_cnt = 1; /* the first entry is the time */
-       tmpl_len = strlen(template);
-       for(i=0;i<=tmpl_len ;i++) {
-           if (template[i] == ':' || template[i] == '\0') {
-               template[i] = '\0';
-               if (tmpl_cnt>rrd.stat_head->ds_cnt){
-                   rrd_set_error("Template contains more DS definitions than RRD");
-                   free(updvals); free(pdp_temp);
-                   free(tmpl_idx); rrd_free(&rrd);
-                   fclose(rrd_file); return(-1);
-               }
-               if ((tmpl_idx[tmpl_cnt++] = ds_match(&rrd,dsname)) == -1){
-                   rrd_set_error("unknown DS name '%s'",dsname);
-                   free(updvals); free(pdp_temp);
-                   free(tmpl_idx); rrd_free(&rrd);
-                   fclose(rrd_file); return(-1);
-               } else {
-                 /* the first element is always the time */
-                 tmpl_idx[tmpl_cnt-1]++; 
-                 /* go to the next entry on the template */
-                 dsname = &template[i+1];
-                  /* fix the damage we did before */
-                  if (i<tmpl_len) {
-                     template[i]=':';
-                  } 
-
-               }
-           }       
-       }
-    }
-    if ((pdp_new = malloc(sizeof(rrd_value_t)
-                         *rrd.stat_head->ds_cnt))==NULL){
-       rrd_set_error("allocating pdp_new ...");
-       free(updvals);
-       free(pdp_temp);
-       free(tmpl_idx);
-       rrd_free(&rrd);
-        fclose(rrd_file);
-       return(-1);
-    }
-
-    /* loop through the arguments. */
-    for(arg_i=optind+1; arg_i<argc;arg_i++) {
-       char *stepper = malloc((strlen(argv[arg_i])+1)*sizeof(char));
-        char *step_start = stepper;
-       char *p;
-       char *parsetime_error = NULL;
-       enum {atstyle, normal} timesyntax;
-       struct time_value ds_tv;
-        if (stepper == NULL){
-                rrd_set_error("failed duplication argv entry");
-                free(updvals);
-                free(pdp_temp);  
-                free(tmpl_idx);
-                rrd_free(&rrd);
-                fclose(rrd_file);
-                return(-1);
-         }
-       /* initialize all ds input to unknown except the first one
-           which has always got to be set */
-       for(ii=1;ii<=rrd.stat_head->ds_cnt;ii++) updvals[ii] = "U";
-       strcpy(stepper,argv[arg_i]);
-       updvals[0]=stepper;
-       /* separate all ds elements; first must be examined separately
-          due to alternate time syntax */
-       if ((p=strchr(stepper,'@'))!=NULL) {
-           timesyntax = atstyle;
-           *p = '\0';
-           stepper = p+1;
-       } else if ((p=strchr(stepper,':'))!=NULL) {
-           timesyntax = normal;
-           *p = '\0';
-           stepper = p+1;
-       } else {
-           rrd_set_error("expected timestamp not found in data source from %s:...",
-                         argv[arg_i]);
-           free(step_start);
-           break;
-       }
-       ii=1;
-       updvals[tmpl_idx[ii]] = stepper;
-       while (*stepper) {
-           if (*stepper == ':') {
-               *stepper = '\0';
-               ii++;
-               if (ii<tmpl_cnt){                   
-                   updvals[tmpl_idx[ii]] = stepper+1;
-               }
-           }
-           stepper++;
-       }
-
-       if (ii != tmpl_cnt-1) {
-           rrd_set_error("expected %lu data source readings (got %lu) from %s:...",
-                         tmpl_cnt-1, ii, argv[arg_i]);
-           free(step_start);
-           break;
-       }
-       
-        /* get the time from the reading ... handle N */
-       if (timesyntax == atstyle) {
-            if ((parsetime_error = parsetime(updvals[0], &ds_tv))) {
-                rrd_set_error("ds time: %s: %s", updvals[0], parsetime_error );
-               free(step_start);
-               break;
-           }
-           if (ds_tv.type == RELATIVE_TO_END_TIME ||
-               ds_tv.type == RELATIVE_TO_START_TIME) {
-               rrd_set_error("specifying time relative to the 'start' "
-                              "or 'end' makes no sense here: %s",
-                             updvals[0]);
-               free(step_start);
-               break;
-           }
-
-           current_time = mktime(&ds_tv.tm) + ds_tv.offset;
-       } else if (strcmp(updvals[0],"N")==0){
-           current_time = time(NULL);
-       } else {
-           current_time = atol(updvals[0]);
-       }
-       
-       if(current_time <= rrd.live_head->last_up){
-           rrd_set_error("illegal attempt to update using time %ld when "
-                         "last update time is %ld (minimum one second step)",
-                         current_time, rrd.live_head->last_up);
-           free(step_start);
-           break;
-       }
-       
-       
-       /* seek to the beginning of the rra's */
-       if (rra_current != rra_begin) {
-           if(fseek(rrd_file, rra_begin, SEEK_SET) != 0) {
-               rrd_set_error("seek error in rrd");
-               free(step_start);
-               break;
-           }
-           rra_current = rra_begin;
-       }
-       rra_start = rra_begin;
-
-       /* when was the current pdp started */
-       proc_pdp_age = rrd.live_head->last_up % rrd.stat_head->pdp_step;
-       proc_pdp_st = rrd.live_head->last_up - proc_pdp_age;
-
-       /* when did the last pdp_st occur */
-       occu_pdp_age = current_time % rrd.stat_head->pdp_step;
-       occu_pdp_st = current_time - occu_pdp_age;
-       interval = current_time - rrd.live_head->last_up;
-    
-       if (occu_pdp_st > proc_pdp_st){
-           /* OK we passed the pdp_st moment*/
-           pre_int =  occu_pdp_st - rrd.live_head->last_up; /* how much of the input data
-                                                             * occurred before the latest
-                                                             * pdp_st moment*/
-           post_int = occu_pdp_age;                         /* how much after it */
-       } else {
-           pre_int = interval;
-           post_int = 0;
-       }
-
-#ifdef DEBUG
-       printf(
-              "proc_pdp_age %lu\t"
-              "proc_pdp_st %lu\t" 
-              "occu_pfp_age %lu\t" 
-              "occu_pdp_st %lu\t"
-              "int %lu\t"
-              "pre_int %lu\t"
-              "post_int %lu\n", proc_pdp_age, proc_pdp_st, 
-               occu_pdp_age, occu_pdp_st,
-              interval, pre_int, post_int);
-#endif
-    
-       /* process the data sources and update the pdp_prep 
-        * area accordingly */
-       for(i=0;i<rrd.stat_head->ds_cnt;i++){
-           enum dst_en dst_idx;
-           dst_idx= dst_conv(rrd.ds_def[i].dst);
-           if((updvals[i+1][0] != 'U') &&
-              rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt >= interval) {
-              double rate = DNAN;
-              /* the data source type defines how to process the data */
-               /* pdp_temp contains rate * time ... eg the bytes
-                * transferred during the interval. Doing it this way saves
-                * a lot of math operations */
-               
-
-               switch(dst_idx){
-               case DST_COUNTER:
-               case DST_DERIVE:
-                   if(rrd.pdp_prep[i].last_ds[0] != 'U'){
-                      pdp_new[i]= rrd_diff(updvals[i+1],rrd.pdp_prep[i].last_ds);
-                      if(dst_idx == DST_COUNTER) {
-                         /* simple overflow catcher sugestet by andres kroonmaa */
-                         /* this will fail terribly for non 32 or 64 bit counters ... */
-                         /* are there any others in SNMP land ? */
-                         if (pdp_new[i] < (double)0.0 ) 
-                           pdp_new[i] += (double)4294967296.0 ;  /* 2^32 */
-                         if (pdp_new[i] < (double)0.0 ) 
-                           pdp_new[i] += (double)18446744069414584320.0; /* 2^64-2^32 */;
-                      }
-                      rate = pdp_new[i] / interval;
-                   }
-                  else {
-                    pdp_new[i]= DNAN;          
-                  }
-                  break;
-               case DST_ABSOLUTE:
-                   pdp_new[i]= atof(updvals[i+1]);
-                   rate = pdp_new[i] / interval;                 
-                   break;
-               case DST_GAUGE:
-                   pdp_new[i] = atof(updvals[i+1]) * interval;
-                   rate = pdp_new[i] / interval;                  
-                   break;
-               default:
-                   rrd_set_error("rrd contains unknown DS type : '%s'",
-                                 rrd.ds_def[i].dst);
-                   break;
-               }
-               /* break out of this for loop if the error string is set */
-               if (rrd_test_error()){
-                   break;
-               }
-              /* make sure pdp_temp is neither too large or too small
-               * if any of these occur it becomes unknown ...
-               * sorry folks ... */
-              if ( ! isnan(rate) && 
-                   (( ! isnan(rrd.ds_def[i].par[DS_max_val].u_val) &&
-                        rate > rrd.ds_def[i].par[DS_max_val].u_val ) ||     
-                   ( ! isnan(rrd.ds_def[i].par[DS_min_val].u_val) &&
-                       rate < rrd.ds_def[i].par[DS_min_val].u_val ))){
-                 pdp_new[i] = DNAN;
-              }               
-           } else {
-               /* no news is news all the same */
-               pdp_new[i] = DNAN;
-           }
-           
-           /* make a copy of the command line argument for the next run */
-#ifdef DEBUG
-           fprintf(stderr,
-                   "prep ds[%lu]\t"
-                   "last_arg '%s'\t"
-                   "this_arg '%s'\t"
-                   "pdp_new %10.2f\n",
-                   i,
-                   rrd.pdp_prep[i].last_ds,
-                   updvals[i+1], pdp_new[i]);
-#endif
-           if(dst_idx == DST_COUNTER || dst_idx == DST_DERIVE){
-               strncpy(rrd.pdp_prep[i].last_ds,
-                       updvals[i+1],LAST_DS_LEN-1);
-               rrd.pdp_prep[i].last_ds[LAST_DS_LEN-1]='\0';
-           }
-       }
-       /* break out of the argument parsing loop if the error_string is set */
-       if (rrd_test_error()){
-           free(step_start);
-           break;
-       }
-       /* has a pdp_st moment occurred since the last run ? */
-
-       if (proc_pdp_st == occu_pdp_st){
-           /* no we have not passed a pdp_st moment. therefore update is simple */
-
-           for(i=0;i<rrd.stat_head->ds_cnt;i++){
-               if(isnan(pdp_new[i]))
-                   rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt += interval;
-               else
-                   rrd.pdp_prep[i].scratch[PDP_val].u_val+= pdp_new[i];
-#ifdef DEBUG
-               fprintf(stderr,
-                       "NO PDP  ds[%lu]\t"
-                       "value %10.2f\t"
-                       "unkn_sec %5lu\n",
-                       i,
-                       rrd.pdp_prep[i].scratch[PDP_val].u_val,
-                       rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt);
-#endif
-           }   
-       } else {
-           /* an pdp_st has occurred. */
-
-           /* in pdp_prep[].scratch[PDP_val].u_val we have collected rate*seconds which 
-            * occurred up to the last run.        
-           pdp_new[] contains rate*seconds from the latest run.
-           pdp_temp[] will contain the rate for cdp */
-
-
-           for(i=0;i<rrd.stat_head->ds_cnt;i++){
-               /* update pdp_prep to the current pdp_st */
-               if(isnan(pdp_new[i]))
-                   rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt += pre_int;
-               else
-                   rrd.pdp_prep[i].scratch[PDP_val].u_val += 
-                       pdp_new[i]/(double)interval*(double)pre_int;
-
-               /* if too much of the pdp_prep is unknown we dump it */
-               if ((rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt 
-                    > rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt) ||
-                   (occu_pdp_st-proc_pdp_st <= 
-                    rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt)) {
-                   pdp_temp[i] = DNAN;
-               } else {
-                   pdp_temp[i] = rrd.pdp_prep[i].scratch[PDP_val].u_val
-                       / (double)( occu_pdp_st
-                                  - proc_pdp_st
-                                  - rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt);
-               }
-               /* make pdp_prep ready for the next run */
-               if(isnan(pdp_new[i])){
-                   rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt = post_int;
-                   rrd.pdp_prep[i].scratch[PDP_val].u_val = 0.0;
-               } else {
-                   rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt = 0;
-                   rrd.pdp_prep[i].scratch[PDP_val].u_val = 
-                       pdp_new[i]/(double)interval*(double)post_int;
-               }
-
-#ifdef DEBUG
-               fprintf(stderr,
-                       "PDP UPD ds[%lu]\t"
-                       "pdp_temp %10.2f\t"
-                       "new_prep %10.2f\t"
-                       "new_unkn_sec %5lu\n",
-                       i, pdp_temp[i],
-                       rrd.pdp_prep[i].scratch[PDP_val].u_val,
-                       rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt);
-#endif
-           }
-
-               /* compute the number of elapsed pdp_st moments */
-               elapsed_pdp_st = (occu_pdp_st - proc_pdp_st) / rrd.stat_head -> pdp_step;
-#ifdef DEBUG
-               fprintf(stderr,"elapsed PDP steps: %lu\n", elapsed_pdp_st);
-#endif
-               if (rra_step_cnt == NULL)
-               {
-                  rra_step_cnt = (unsigned long *) 
-                         malloc((rrd.stat_head->rra_cnt)* sizeof(unsigned long));
-               }
-
-           for(i = 0, rra_start = rra_begin;
-               i < rrd.stat_head->rra_cnt;
-           rra_start += rrd.rra_def[i].row_cnt * rrd.stat_head -> ds_cnt * sizeof(rrd_value_t),
-               i++)
-               {
-               current_cf = cf_conv(rrd.rra_def[i].cf_nam);
-               start_pdp_offset = rrd.rra_def[i].pdp_cnt -
-                  (proc_pdp_st / rrd.stat_head -> pdp_step) % rrd.rra_def[i].pdp_cnt;
-        if (start_pdp_offset <= elapsed_pdp_st) {
-           rra_step_cnt[i] = (elapsed_pdp_st - start_pdp_offset) / 
-                     rrd.rra_def[i].pdp_cnt + 1;
-           } else {
-                  rra_step_cnt[i] = 0;
-               }
-
-               if (current_cf == CF_SEASONAL || current_cf == CF_DEVSEASONAL) 
-               {
-                  /* If this is a bulk update, we need to skip ahead in the seasonal
-                       * arrays so that they will be correct for the next observed value;
-                       * note that for the bulk update itself, no update will occur to
-                       * DEVSEASONAL or SEASONAL; futhermore, HWPREDICT and DEVPREDICT will
-                       * be set to DNAN. */
-           if (rra_step_cnt[i] > 2) 
-                  {
-                         /* skip update by resetting rra_step_cnt[i],
-                          * note that this is not data source specific; this is due
-                          * to the bulk update, not a DNAN value for the specific data
-                          * source. */
-                         rra_step_cnt[i] = 0;
-              lookup_seasonal(&rrd,i,rra_start,rrd_file,elapsed_pdp_st, 
-                            &last_seasonal_coef);
-                     lookup_seasonal(&rrd,i,rra_start,rrd_file,elapsed_pdp_st + 1,
-                            &seasonal_coef);
-                  }
-               
-                 /* periodically run a smoother for seasonal effects */
-                 /* Need to use first cdp parameter buffer to track
-                  * burnin (burnin requires a specific smoothing schedule).
-                  * The CDP_init_seasonal parameter is really an RRA level,
-                  * not a data source within RRA level parameter, but the rra_def
-                  * is read only for rrd_update (not flushed to disk). */
-                 iii = i*(rrd.stat_head -> ds_cnt);
-                 if (rrd.cdp_prep[iii].scratch[CDP_init_seasonal].u_cnt 
-                         <= BURNIN_CYCLES)
-                 {
-                    if (rrd.rra_ptr[i].cur_row + elapsed_pdp_st 
-                                > rrd.rra_def[i].row_cnt - 1) {
-                          /* mark off one of the burnin cycles */
-                          ++(rrd.cdp_prep[iii].scratch[CDP_init_seasonal].u_cnt);
-                      schedule_smooth = 1;
-                        }  
-                 } else {
-                        /* someone has no doubt invented a trick to deal with this
-                         * wrap around, but at least this code is clear. */
-                        if (rrd.rra_def[i].par[RRA_seasonal_smooth_idx].u_cnt >
-                            rrd.rra_ptr[i].cur_row)
-                        {
-                                /* here elapsed_pdp_st = rra_step_cnt[i] because of 1-1
-                                 * mapping between PDP and CDP */
-                                if (rrd.rra_ptr[i].cur_row + elapsed_pdp_st
-                                       >= rrd.rra_def[i].par[RRA_seasonal_smooth_idx].u_cnt)
-                                {
-#ifdef DEBUG
-                                       fprintf(stderr,
-                                       "schedule_smooth 1: cur_row %lu, elapsed_pdp_st %lu, smooth idx %lu\n",
-                    rrd.rra_ptr[i].cur_row, elapsed_pdp_st, 
-                                       rrd.rra_def[i].par[RRA_seasonal_smooth_idx].u_cnt);
-#endif
-                                       schedule_smooth = 1;
-                                }
-             } else {
-                                /* can't rely on negative numbers because we are working with
-                                 * unsigned values */
-                                /* Don't need modulus here. If we've wrapped more than once, only
-                                 * one smooth is executed at the end. */
-                                if (rrd.rra_ptr[i].cur_row + elapsed_pdp_st >= rrd.rra_def[i].row_cnt
-                                       && rrd.rra_ptr[i].cur_row + elapsed_pdp_st - rrd.rra_def[i].row_cnt
-                                       >= rrd.rra_def[i].par[RRA_seasonal_smooth_idx].u_cnt)
-                                {
-#ifdef DEBUG
-                                       fprintf(stderr,
-                                       "schedule_smooth 2: cur_row %lu, elapsed_pdp_st %lu, smooth idx %lu\n",
-                    rrd.rra_ptr[i].cur_row, elapsed_pdp_st, 
-                                       rrd.rra_def[i].par[RRA_seasonal_smooth_idx].u_cnt);
-#endif
-                                       schedule_smooth = 1;
-                                }
-                        }
-                 }
-
-             rra_current = ftell(rrd_file); 
-               } /* if cf is DEVSEASONAL or SEASONAL */
-
-        if (rrd_test_error()) break;
-
-                   /* update CDP_PREP areas */
-                   /* loop over data soures within each RRA */
-                   for(ii = 0;
-                       ii < rrd.stat_head->ds_cnt;
-                       ii++)
-                       {
-                       
-                       /* iii indexes the CDP prep area for this data source within the RRA */
-                       iii=i*rrd.stat_head->ds_cnt+ii;
-
-                       if (rrd.rra_def[i].pdp_cnt > 1) {
-                         
-                          if (rra_step_cnt[i] > 0) {
-                          /* If we are in this block, as least 1 CDP value will be written to
-                               * disk, this is the CDP_primary_val entry. If more than 1 value needs
-                               * to be written, then the "fill in" value is the CDP_secondary_val
-                               * entry. */
-                                 if (isnan(pdp_temp[ii]))
-                  {
-                                        rrd.cdp_prep[iii].scratch[CDP_unkn_pdp_cnt].u_cnt += start_pdp_offset;
-                                        rrd.cdp_prep[iii].scratch[CDP_secondary_val].u_val = DNAN;
-                                 } else {
-                                        /* CDP_secondary value is the RRA "fill in" value for intermediary
-                                         * CDP data entries. No matter the CF, the value is the same because
-                                         * the average, max, min, and last of a list of identical values is
-                                         * the same, namely, the value itself. */
-                                        rrd.cdp_prep[iii].scratch[CDP_secondary_val].u_val = pdp_temp[ii];
-                                 }
-                     
-                                 if (rrd.cdp_prep[iii].scratch[CDP_unkn_pdp_cnt].u_cnt
-                                     > rrd.rra_def[i].pdp_cnt*
-                                     rrd.rra_def[i].par[RRA_cdp_xff_val].u_val)
-                                 {
-                                        rrd.cdp_prep[iii].scratch[CDP_primary_val].u_val = DNAN;
-                                        /* initialize carry over */
-                                        if (current_cf == CF_AVERAGE) {
-                                                  if (isnan(pdp_temp[ii])) { 
-                                                         rrd.cdp_prep[iii].scratch[CDP_val].u_val = DNAN;
-                                                  } else {
-                                                         rrd.cdp_prep[iii].scratch[CDP_val].u_val = pdp_temp[ii] *
-                                                                ((elapsed_pdp_st - start_pdp_offset) % rrd.rra_def[i].pdp_cnt);
-                                                  }
-                                        } else {
-                                               rrd.cdp_prep[iii].scratch[CDP_val].u_val = pdp_temp[ii];
-                                        }
-                                 } else {
-                                        rrd_value_t cum_val, cur_val; 
-                                    switch (current_cf) {
-                                               case CF_AVERAGE:
-                                                 cum_val = IFDNAN(rrd.cdp_prep[iii].scratch[CDP_val].u_val, 0.0);
-                                                 cur_val = IFDNAN(pdp_temp[ii],0.0);
-                          rrd.cdp_prep[iii].scratch[CDP_primary_val].u_val =
-                                              (cum_val + cur_val) /
-                                          (rrd.rra_def[i].pdp_cnt
-                                              -rrd.cdp_prep[iii].scratch[CDP_unkn_pdp_cnt].u_cnt);
-                                                  /* initialize carry over value */
-                                                  if (isnan(pdp_temp[ii])) { 
-                                                         rrd.cdp_prep[iii].scratch[CDP_val].u_val = DNAN;
-                                                  } else {
-                                                         rrd.cdp_prep[iii].scratch[CDP_val].u_val = pdp_temp[ii] *
-                                                                ((elapsed_pdp_st - start_pdp_offset) % rrd.rra_def[i].pdp_cnt);
-                                                  }
-                                                  break;
-                                               case CF_MAXIMUM:
-                                                 cum_val = IFDNAN(rrd.cdp_prep[iii].scratch[CDP_val].u_val, -DINF);
-                                                 cur_val = IFDNAN(pdp_temp[ii],-DINF);
-#ifdef DEBUG
-                                                 if (isnan(rrd.cdp_prep[iii].scratch[CDP_val].u_val) &&
-                                                         isnan(pdp_temp[ii])) {
-                                                    fprintf(stderr,
-                                                               "RRA %lu, DS %lu, both CDP_val and pdp_temp are DNAN!",
-                                                               i,ii);
-                                                        exit(-1);
-                                                 }
-#endif
-                                                 if (cur_val > cum_val)
-                                                        rrd.cdp_prep[iii].scratch[CDP_primary_val].u_val = cur_val;
-                                                 else
-                                                        rrd.cdp_prep[iii].scratch[CDP_primary_val].u_val = cum_val;
-                                                 /* initialize carry over value */
-                                                 rrd.cdp_prep[iii].scratch[CDP_val].u_val = pdp_temp[ii];
-                                                 break;
-                                               case CF_MINIMUM:
-                                                 cum_val = IFDNAN(rrd.cdp_prep[iii].scratch[CDP_val].u_val, DINF);
-                                                 cur_val = IFDNAN(pdp_temp[ii],DINF);
-#ifdef DEBUG
-                                                 if (isnan(rrd.cdp_prep[iii].scratch[CDP_val].u_val) &&
-                                                         isnan(pdp_temp[ii])) {
-                                                    fprintf(stderr,
-                                                               "RRA %lu, DS %lu, both CDP_val and pdp_temp are DNAN!",
-                                                               i,ii);
-                                                        exit(-1);
-                                                 }
-#endif
-                                                 if (cur_val < cum_val)
-                                                        rrd.cdp_prep[iii].scratch[CDP_primary_val].u_val = cur_val;
-                                                 else
-                                                        rrd.cdp_prep[iii].scratch[CDP_primary_val].u_val = cum_val;
-                                                 /* initialize carry over value */
-                                                 rrd.cdp_prep[iii].scratch[CDP_val].u_val = pdp_temp[ii];
-                                                 break;
-                                               case CF_LAST:
-                                               default:
-                                                  rrd.cdp_prep[iii].scratch[CDP_primary_val].u_val = pdp_temp[ii];
-                                                  /* initialize carry over value */
-                                                  rrd.cdp_prep[iii].scratch[CDP_val].u_val = pdp_temp[ii];
-                                               break;
-                                        }
-                                 } /* endif meets xff value requirement for a valid value */
-                                 /* initialize carry over CDP_unkn_pdp_cnt, this must after CDP_primary_val
-                                  * is set because CDP_unkn_pdp_cnt is required to compute that value. */
-                                 if (isnan(pdp_temp[ii]))
-                                        rrd.cdp_prep[iii].scratch[CDP_unkn_pdp_cnt].u_cnt = 
-                                               (elapsed_pdp_st - start_pdp_offset) % rrd.rra_def[i].pdp_cnt;
-                                 else
-                                        rrd.cdp_prep[iii].scratch[CDP_unkn_pdp_cnt].u_cnt = 0;
-               } else  /* rra_step_cnt[i]  == 0 */
-                          {
-#ifdef DEBUG
-                                 if (isnan(rrd.cdp_prep[iii].scratch[CDP_val].u_val)) {
-                                 fprintf(stderr,"schedule CDP_val update, RRA %lu DS %lu, DNAN\n",
-                                        i,ii);
-                                 } else {
-                                 fprintf(stderr,"schedule CDP_val update, RRA %lu DS %lu, %10.2f\n",
-                                        i,ii,rrd.cdp_prep[iii].scratch[CDP_val].u_val);
-                                 }
-#endif
-                                 if (isnan(pdp_temp[ii])) {
-                                rrd.cdp_prep[iii].scratch[CDP_unkn_pdp_cnt].u_cnt += elapsed_pdp_st;
-                                 } else if (isnan(rrd.cdp_prep[iii].scratch[CDP_val].u_val))
-                                 {
-                                        if (current_cf == CF_AVERAGE) {
-                                           rrd.cdp_prep[iii].scratch[CDP_val].u_val = pdp_temp[ii] *
-                                                  elapsed_pdp_st;
-                                        } else {
-                                           rrd.cdp_prep[iii].scratch[CDP_val].u_val = pdp_temp[ii];
-                                        }
-#ifdef DEBUG
-                                        fprintf(stderr,"Initialize CDP_val for RRA %lu DS %lu: %10.2f\n",
-                                           i,ii,rrd.cdp_prep[iii].scratch[CDP_val].u_val);
-#endif
-                                 } else {
-                                        switch (current_cf) {
-                                        case CF_AVERAGE:
-                                           rrd.cdp_prep[iii].scratch[CDP_val].u_val += pdp_temp[ii] *
-                                                  elapsed_pdp_st;
-                                               break;
-                                        case CF_MINIMUM:
-                                               if (pdp_temp[ii] < rrd.cdp_prep[iii].scratch[CDP_val].u_val)
-                                                  rrd.cdp_prep[iii].scratch[CDP_val].u_val = pdp_temp[ii];
-                                               break; 
-                                        case CF_MAXIMUM:
-                                               if (pdp_temp[ii] > rrd.cdp_prep[iii].scratch[CDP_val].u_val)
-                                                  rrd.cdp_prep[iii].scratch[CDP_val].u_val = pdp_temp[ii];
-                                               break; 
-                                        case CF_LAST:
-                                        default:
-                                               rrd.cdp_prep[iii].scratch[CDP_val].u_val = pdp_temp[ii];
-                                               break;
-                                        }
-                                 }
-                          }
-                       } else { /* rrd.rra_def[i].pdp_cnt == 1 */
-                          if (elapsed_pdp_st > 2)
-                          {
-                                  switch (current_cf) {
-                                  case CF_AVERAGE:
-                                  default:
-                                 rrd.cdp_prep[iii].scratch[CDP_primary_val].u_val=pdp_temp[ii];
-                                 rrd.cdp_prep[iii].scratch[CDP_secondary_val].u_val=pdp_temp[ii];
-                                         break;
-                   case CF_SEASONAL:
-                                  case CF_DEVSEASONAL:
-                                         /* need to update cached seasonal values, so they are consistent
-                                          * with the bulk update */
-                      /* WARNING: code relies on the fact that CDP_hw_last_seasonal and
-                                          * CDP_last_deviation are the same. */
-                      rrd.cdp_prep[iii].scratch[CDP_hw_last_seasonal].u_val =
-                                                last_seasonal_coef[ii];
-                                         rrd.cdp_prep[iii].scratch[CDP_hw_seasonal].u_val =
-                                                seasonal_coef[ii];
-                                         break;
-                   case CF_HWPREDICT:
-                                         /* need to update the null_count and last_null_count.
-                                          * even do this for non-DNAN pdp_temp because the
-                                          * algorithm is not learning from batch updates. */
-                                         rrd.cdp_prep[iii].scratch[CDP_null_count].u_cnt += 
-                                                elapsed_pdp_st;
-                                         rrd.cdp_prep[iii].scratch[CDP_last_null_count].u_cnt += 
-                                                elapsed_pdp_st - 1;
-                                         /* fall through */
-                                  case CF_DEVPREDICT:
-                                 rrd.cdp_prep[iii].scratch[CDP_primary_val].u_val = DNAN;
-                                 rrd.cdp_prep[iii].scratch[CDP_secondary_val].u_val = DNAN;
-                                         break;
-                   case CF_FAILURES:
-                                         /* do not count missed bulk values as failures */
-                                 rrd.cdp_prep[iii].scratch[CDP_primary_val].u_val = 0;
-                                 rrd.cdp_prep[iii].scratch[CDP_secondary_val].u_val = 0;
-                                         /* need to reset violations buffer.
-                                          * could do this more carefully, but for now, just
-                                          * assume a bulk update wipes away all violations. */
-                      erase_violations(&rrd, iii, i);
-                                         break;
-                                  }
-                          } 
-                       } /* endif rrd.rra_def[i].pdp_cnt == 1 */
-
-                       if (rrd_test_error()) break;
-
-                       } /* endif data sources loop */
-        } /* end RRA Loop */
-
-               /* this loop is only entered if elapsed_pdp_st < 3 */
-               for (j = elapsed_pdp_st, scratch_idx = CDP_primary_val; 
-                        j > 0 && j < 3; j--, scratch_idx = CDP_secondary_val)
-               {
-              for(i = 0, rra_start = rra_begin;
-                  i < rrd.stat_head->rra_cnt;
-              rra_start += rrd.rra_def[i].row_cnt * rrd.stat_head -> ds_cnt * sizeof(rrd_value_t),
-                  i++)
-                  {
-                         if (rrd.rra_def[i].pdp_cnt > 1) continue;
-
-                 current_cf = cf_conv(rrd.rra_def[i].cf_nam);
-                         if (current_cf == CF_SEASONAL || current_cf == CF_DEVSEASONAL)
-                         {
-                        lookup_seasonal(&rrd,i,rra_start,rrd_file,
-                                   elapsed_pdp_st + (scratch_idx == CDP_primary_val ? 1 : 2),
-                               &seasonal_coef);
-                         }
-                         if (rrd_test_error()) break;
-                     /* loop over data soures within each RRA */
-                     for(ii = 0;
-                         ii < rrd.stat_head->ds_cnt;
-                         ii++)
-                         {
-                            update_aberrant_CF(&rrd,pdp_temp[ii],current_cf,
-                                       i*(rrd.stat_head->ds_cnt) + ii,i,ii,
-                                   scratch_idx, seasonal_coef);
-                         }
-           } /* end RRA Loop */
-                  if (rrd_test_error()) break;
-           } /* end elapsed_pdp_st loop */
-
-               if (rrd_test_error()) break;
-
-               /* Ready to write to disk */
-               /* Move sequentially through the file, writing one RRA at a time.
-                * Note this architecture divorces the computation of CDP with
-                * flushing updated RRA entries to disk. */
-           for(i = 0, rra_start = rra_begin;
-               i < rrd.stat_head->rra_cnt;
-           rra_start += rrd.rra_def[i].row_cnt * rrd.stat_head -> ds_cnt * sizeof(rrd_value_t),
-               i++) {
-               /* is there anything to write for this RRA? If not, continue. */
-        if (rra_step_cnt[i] == 0) continue;
-
-               /* write the first row */
-#ifdef DEBUG
-        fprintf(stderr,"  -- RRA Preseek %ld\n",ftell(rrd_file));
-#endif
-           rrd.rra_ptr[i].cur_row++;
-           if (rrd.rra_ptr[i].cur_row >= rrd.rra_def[i].row_cnt)
-                  rrd.rra_ptr[i].cur_row = 0; /* wrap around */
-               /* positition on the first row */
-               rra_pos_tmp = rra_start +
-                  (rrd.stat_head->ds_cnt)*(rrd.rra_ptr[i].cur_row)*sizeof(rrd_value_t);
-               if(rra_pos_tmp != rra_current) {
-                  if(fseek(rrd_file, rra_pos_tmp, SEEK_SET) != 0){
-                     rrd_set_error("seek error in rrd");
-                     break;
-                  }
-                  rra_current = rra_pos_tmp;
-               }
-#ifdef DEBUG
-           fprintf(stderr,"  -- RRA Postseek %ld\n",ftell(rrd_file));
-#endif
-               scratch_idx = CDP_primary_val;
-               write_RRA_row(&rrd, i, &rra_current, scratch_idx, rrd_file);
-               if (rrd_test_error()) break;
-
-               /* write other rows of the bulk update, if any */
-               scratch_idx = CDP_secondary_val;
-               for ( ; rra_step_cnt[i] > 1; 
-                    rra_step_cnt[i]--, rrd.rra_ptr[i].cur_row++)
-               {
-                  if (rrd.rra_ptr[i].cur_row == rrd.rra_def[i].row_cnt)
-                  {
-#ifdef DEBUG
-              fprintf(stderr,"Wraparound for RRA %s, %lu updates left\n",
-                         rrd.rra_def[i].cf_nam, rra_step_cnt[i] - 1);
-#endif
-                         /* wrap */
-                         rrd.rra_ptr[i].cur_row = 0;
-                         /* seek back to beginning of current rra */
-                     if (fseek(rrd_file, rra_start, SEEK_SET) != 0)
-                         {
-                        rrd_set_error("seek error in rrd");
-                        break;
-                         }
-#ifdef DEBUG
-                 fprintf(stderr,"  -- Wraparound Postseek %ld\n",ftell(rrd_file));
-#endif
-                         rra_current = rra_start;
-                  }
-                  write_RRA_row(&rrd, i, &rra_current, scratch_idx, rrd_file);
-               }
-               
-               if (rrd_test_error())
-                 break;
-               } /* RRA LOOP */
-
-           /* break out of the argument parsing loop if error_string is set */
-           if (rrd_test_error()){
-                  free(step_start);
-                  break;
-           } 
-           
-       } /* endif a pdp_st has occurred */ 
-       rrd.live_head->last_up = current_time;
-       free(step_start);
-    } /* function argument loop */
-
-    if (seasonal_coef != NULL) free(seasonal_coef);
-    if (last_seasonal_coef != NULL) free(last_seasonal_coef);
-       if (rra_step_cnt != NULL) free(rra_step_cnt);
-
-    /* if we got here and if there is an error and if the file has not been
-     * written to, then close things up and return. */
-    if (rrd_test_error()) {
-       free(updvals);
-       free(tmpl_idx);
-       rrd_free(&rrd);
-       free(pdp_temp);
-       free(pdp_new);
-        fclose(rrd_file);
-       return(-1);
-    }
-
-    /* aargh ... that was tough ... so many loops ... anyway, its done.
-     * we just need to write back the live header portion now*/
-
-    if (fseek(rrd_file, (sizeof(stat_head_t)
-                        + sizeof(ds_def_t)*rrd.stat_head->ds_cnt 
-                        + sizeof(rra_def_t)*rrd.stat_head->rra_cnt),
-             SEEK_SET) != 0) {
-       rrd_set_error("seek rrd for live header writeback");
-       free(updvals);
-       free(tmpl_idx);
-       rrd_free(&rrd);
-       free(pdp_temp);
-       free(pdp_new);
-        fclose(rrd_file);
-       return(-1);
-    }
-
-    if(fwrite( rrd.live_head,
-              sizeof(live_head_t), 1, rrd_file) != 1){
-       rrd_set_error("fwrite live_head to rrd");
-       free(updvals);
-       rrd_free(&rrd);
-       free(tmpl_idx);
-       free(pdp_temp);
-       free(pdp_new);
-        fclose(rrd_file);
-       return(-1);
-    }
-
-    if(fwrite( rrd.pdp_prep,
-              sizeof(pdp_prep_t),
-              rrd.stat_head->ds_cnt, rrd_file) != rrd.stat_head->ds_cnt){
-       rrd_set_error("ftwrite pdp_prep to rrd");
-       free(updvals);
-       rrd_free(&rrd);
-       free(tmpl_idx);
-       free(pdp_temp);
-       free(pdp_new);
-        fclose(rrd_file);
-       return(-1);
-    }
-
-    if(fwrite( rrd.cdp_prep,
-              sizeof(cdp_prep_t),
-              rrd.stat_head->rra_cnt *rrd.stat_head->ds_cnt, rrd_file) 
-       != rrd.stat_head->rra_cnt *rrd.stat_head->ds_cnt){
-
-       rrd_set_error("ftwrite cdp_prep to rrd");
-       free(updvals);
-       free(tmpl_idx);
-       rrd_free(&rrd);
-       free(pdp_temp);
-       free(pdp_new);
-        fclose(rrd_file);
-       return(-1);
-    }
-
-    if(fwrite( rrd.rra_ptr,
-              sizeof(rra_ptr_t), 
-              rrd.stat_head->rra_cnt,rrd_file) != rrd.stat_head->rra_cnt){
-       rrd_set_error("fwrite rra_ptr to rrd");
-       free(updvals);
-       free(tmpl_idx);
-       rrd_free(&rrd);
-       free(pdp_temp);
-       free(pdp_new);
-        fclose(rrd_file);
-       return(-1);
-    }
-
-    /* OK now close the files and free the memory */
-    if(fclose(rrd_file) != 0){
-       rrd_set_error("closing rrd");
-       free(updvals);
-       free(tmpl_idx);
-       rrd_free(&rrd);
-       free(pdp_temp);
-       free(pdp_new);
-       return(-1);
-    }
-
-    /* calling the smoothing code here guarantees at most
-        * one smoothing operation per rrd_update call. Unfortunately,
-        * it is possible with bulk updates, or a long-delayed update
-        * for smoothing to occur off-schedule. This really isn't
-        * critical except during the burning cycles. */
-       if (schedule_smooth)
-       {
-#ifndef WIN32
-         rrd_file = fopen(argv[optind],"r+");
-#else
-         rrd_file = fopen(argv[optind],"rb+");
-#endif
-         rra_start = rra_begin;
-         for (i = 0; i < rrd.stat_head -> rra_cnt; ++i)
-         {
-           if (cf_conv(rrd.rra_def[i].cf_nam) == CF_DEVSEASONAL ||
-               cf_conv(rrd.rra_def[i].cf_nam) == CF_SEASONAL)
-           {
-#ifdef DEBUG
-             fprintf(stderr,"Running smoother for rra %ld\n",i);
-#endif
-             apply_smoother(&rrd,i,rra_start,rrd_file);
-             if (rrd_test_error())
-               break;
-           }
-           rra_start += rrd.rra_def[i].row_cnt
-             *rrd.stat_head->ds_cnt*sizeof(rrd_value_t);
-         }
-         fclose(rrd_file);
-       }
-    rrd_free(&rrd);
-    free(updvals);
-    free(tmpl_idx);
-    free(pdp_new);
-    free(pdp_temp);
-    return(0);
-}
-
-/*
- * get exclusive lock to whole file.
- * lock gets removed when we close the file
- *
- * returns 0 on success
- */
-int
-LockRRD(FILE *rrdfile)
-{
-    int        rrd_fd;         /* File descriptor for RRD */
-    int                        stat;
-
-    rrd_fd = fileno(rrdfile);
-
-       {
-#ifndef WIN32    
-               struct flock    lock;
-    lock.l_type = F_WRLCK;    /* exclusive write lock */
-    lock.l_len = 0;          /* whole file */
-    lock.l_start = 0;        /* start of file */
-    lock.l_whence = SEEK_SET;   /* end of file */
-
-    stat = fcntl(rrd_fd, F_SETLK, &lock);
-#else
-               struct _stat st;
-
-               if ( _fstat( rrd_fd, &st ) == 0 ) {
-                       stat = _locking ( rrd_fd, _LK_NBLCK, st.st_size );
-               } else {
-                       stat = -1;
-               }
-#endif
-       }
-
-    return(stat);
-}
-
-
-void
-write_RRA_row (rrd_t *rrd, unsigned long rra_idx, unsigned long *rra_current,
-   unsigned short CDP_scratch_idx, FILE *rrd_file)
-{
-   unsigned long ds_idx, cdp_idx;
-
-   for (ds_idx = 0; ds_idx < rrd -> stat_head -> ds_cnt; ds_idx++)
-   {
-      /* compute the cdp index */
-      cdp_idx =rra_idx * (rrd -> stat_head->ds_cnt) + ds_idx;
-#ifdef DEBUG
-         fprintf(stderr,"  -- RRA WRITE VALUE %e, at %ld CF:%s\n",
-            rrd -> cdp_prep[cdp_idx].scratch[CDP_scratch_idx].u_val,ftell(rrd_file),
-            rrd -> rra_def[rra_idx].cf_nam);
-#endif
-
-         if(fwrite(&(rrd -> cdp_prep[cdp_idx].scratch[CDP_scratch_idx].u_val),
-                sizeof(rrd_value_t),1,rrd_file) != 1)
-         { 
-            rrd_set_error("writing rrd");
-                return;
-         }
-         *rra_current += sizeof(rrd_value_t);
-       }
-}
diff --git a/src/strftime.c b/src/strftime.c
new file mode 100644 (file)
index 0000000..c57a726
--- /dev/null
@@ -0,0 +1,356 @@
+/**
+ *
+ * strftime.c
+ *
+ * implements the ansi c function strftime()
+ *
+ * written 6 september 1989 by jim nutt
+ * released into the public domain by jim nutt
+ *
+ * modified 21-Oct-89 by Rob Duff
+ *
+ * modified 08-Dec-04 by Tobi Oetiker (added %V)
+**/
+
+#include <stddef.h>     /* for size_t */
+#include <stdarg.h>     /* for va_arg */
+#include <time.h>       /* for struct tm */
+#include "strftime.h"
+
+/* Define your own defaults in config.h if necessary */
+#if defined(TZNAME_STD) && defined(TZNAME_DST)
+char *tzname_[2] = {TZNAME_STD, TZNAME_DST};
+#else
+#define tzname_ tzname
+#endif
+
+static char *aday[] = {
+    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+};
+
+static char *day[] = {
+    "Sunday", "Monday", "Tuesday", "Wednesday",
+    "Thursday", "Friday", "Saturday"
+};
+
+static char *amonth[] = {
+    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+static char *month[] = {
+    "January", "February", "March", "April", "May", "June",
+    "July", "August", "September", "October", "November", "December"
+};
+
+static char buf[26];
+
+static void strfmt(char *str, const char *fmt, ...);
+
+/**
+ *
+ * size_t strftime_(char *str,
+ *                  size_t maxs,
+ *                  const char *fmt,
+ *                  const struct tm *t)
+ *
+ *      this functions acts much like a sprintf for time/date output.
+ *      given a pointer to an output buffer, a format string and a
+ *      time, it copies the time to the output buffer formatted in
+ *      accordance with the format string.  the parameters are used
+ *      as follows:
+ *
+ *          str is a pointer to the output buffer, there should
+ *          be at least maxs characters available at the address
+ *          pointed to by str.
+ *
+ *          maxs is the maximum number of characters to be copied
+ *          into the output buffer, included the '\0' terminator
+ *
+ *          fmt is the format string.  a percent sign (%) is used
+ *          to indicate that the following character is a special
+ *          format character.  the following are valid format
+ *          characters:
+ *
+ *              %A      full weekday name (Monday)
+ *              %a      abbreviated weekday name (Mon)
+ *              %B      full month name (January)
+ *              %b      abbreviated month name (Jan)
+ *              %c      standard date and time representation
+ *              %d      day-of-month (01-31)
+ *              %H      hour (24 hour clock) (00-23)
+ *              %I      hour (12 hour clock) (01-12)
+ *              %j      day-of-year (001-366)
+ *              %M      minute (00-59)
+ *              %m      month (01-12)
+ *              %p      local equivalent of AM or PM
+ *              %S      second (00-59)
+ *              %U      week-of-year, first day sunday (00-53)
+ *              %W      week-of-year, first day monday (00-53)
+ *              %V      ISO 8601 Week number 
+ *              %w      weekday (0-6, sunday is 0)
+ *              %X      standard time representation
+ *              %x      standard date representation
+ *              %Y      year with century
+ *              %y      year without century (00-99)
+ *              %Z      timezone name
+ *              %%      percent sign
+ *
+ *      the standard date string is equivalent to:
+ *
+ *          %a %b %d %Y
+ *
+ *      the standard time string is equivalent to:
+ *
+ *          %H:%M:%S
+ *
+ *      the standard date and time string is equivalent to:
+ *
+ *          %a %b %d %H:%M:%S %Y
+ *
+ *      strftime_() returns the number of characters placed in the
+ *      buffer, not including the terminating \0, or zero if more
+ *      than maxs characters were produced.
+ *
+**/
+
+size_t strftime_(char *s, size_t maxs, const char *f, const struct tm *t)
+{
+      int w,d;
+      char *p, *q, *r;
+
+      p = s;
+      q = s + maxs - 1;
+      while ((*f != '\0'))
+      {
+            if (*f++ == '%')
+            {
+                  r = buf;
+                  switch (*f++)
+                  {
+                  case '%' :
+                        r = "%";
+                        break;
+
+                  case 'a' :
+                        r = aday[t->tm_wday];
+                        break;
+
+                  case 'A' :
+                        r = day[t->tm_wday];
+                        break;
+
+                  case 'b' :
+                        r = amonth[t->tm_mon];
+                        break;
+
+                  case 'B' :
+                        r = month[t->tm_mon];
+                        break;
+
+                  case 'c' :
+                        strfmt(r, "%0 %0 %2 %2:%2:%2 %4",
+                              aday[t->tm_wday], amonth[t->tm_mon],
+                              t->tm_mday,t->tm_hour, t->tm_min,
+                              t->tm_sec, t->tm_year+1900);
+                        break;
+
+                  case 'd' :
+                        strfmt(r,"%2",t->tm_mday);
+                        break;
+
+                  case 'H' :
+                        strfmt(r,"%2",t->tm_hour);
+                        break;
+
+                  case 'I' :
+                        strfmt(r,"%2",(t->tm_hour%12)?t->tm_hour%12:12);
+                        break;
+
+                  case 'j' :
+                        strfmt(r,"%3",t->tm_yday+1);
+                        break;
+
+                  case 'm' :
+                        strfmt(r,"%2",t->tm_mon+1);
+                        break;
+
+                  case 'M' :
+                        strfmt(r,"%2",t->tm_min);
+                        break;
+
+                  case 'p' :
+                        r = (t->tm_hour>11)?"PM":"AM";
+                        break;
+
+                  case 'S' :
+                        strfmt(r,"%2",t->tm_sec);
+                        break;
+
+                  case 'U' :
+                        w = t->tm_yday/7;
+                        if (t->tm_yday%7 > t->tm_wday)
+                              w++;
+                        strfmt(r, "%2", w);
+                        break;
+
+                  case 'W' :
+                        w = t->tm_yday/7;
+                        if (t->tm_yday%7 > (t->tm_wday+6)%7)
+                              w++;
+                        strfmt(r, "%2", w);
+                        break;
+
+                  case 'V':
+
+                        /* ISO 8601 Week Of Year:
+                           If the week (Monday - Sunday) containing January 1 has four or more
+                           days in the new year, then it is week 1; otherwise it is week 53 of
+                           the previous year and the next week is week one. */
+
+                       w  =  (t->tm_yday + 7 - (t->tm_wday ? t->tm_wday - 1 : 6)) / 7;
+                        d  =  (t->tm_yday + 7 - (t->tm_wday ? t->tm_wday - 1 : 6)) % 7;
+
+                        if (d >= 4) { w++; } else if (w == 0) { w = 53; }
+                        strfmt(r, "%2", w);
+                        break;
+
+                  case 'w' :
+                        strfmt(r,"%1",t->tm_wday);
+                        break;
+
+                  case 'x' :
+                        strfmt(r, "%3s %3s %2 %4", aday[t->tm_wday],
+                              amonth[t->tm_mon], t->tm_mday, t->tm_year+1900);
+                        break;
+
+                  case 'X' :
+                        strfmt(r, "%2:%2:%2", t->tm_hour,
+                              t->tm_min, t->tm_sec);
+                        break;
+
+                  case 'y' :
+                        strfmt(r,"%2",t->tm_year%100);
+                        break;
+
+                  case 'Y' :
+                        strfmt(r,"%4",t->tm_year+1900);
+                        break;
+
+                  case 'Z' :
+                        r = (t->tm_isdst && tzname_[1][0]) ?
+                              tzname_[1] : tzname_[0];
+                        break;
+
+                  default:
+                        buf[0] = '%';     /* reconstruct the format */
+                        buf[1] = f[-1];
+                        buf[2] = '\0';
+                        if (buf[1] == 0)
+                              f--;        /* back up if at end of string */
+                  }
+                  while (*r)
+                  {
+                        if (p == q)
+                        {
+                              *q = '\0';
+                              return 0;
+                        }
+                        *p++ = *r++;
+                  }
+            }
+            else
+            {
+                  if (p == q)
+                  {
+                        *q = '\0';
+                        return 0;
+                  }
+                  *p++ = f[-1];
+            }
+      }
+      *p = '\0';
+      return p - s;
+}
+
+/*
+ *  stdarg.h
+ *
+typedef void *va_list;
+#define va_start(vp,v) (vp=((char*)&v)+sizeof(v))
+#define va_arg(vp,t) (*((t*)(vp))++)
+#define va_end(vp)
+ *
+ */
+
+static int powers[5] = { 1, 10, 100, 1000, 10000 };
+
+/**
+ * static void strfmt(char *str, char *fmt);
+ *
+ * simple sprintf for strftime
+ *
+ * each format descriptor is of the form %n
+ * where n goes from zero to four
+ *
+ * 0    -- string %s
+ * 1..4 -- int %?.?d
+ *
+**/
+
+static void strfmt(char *str, const char *fmt, ...)
+{
+      int ival, ilen;
+      char *sval;
+      va_list vp;
+
+      va_start(vp, fmt);
+      while (*fmt)
+      {
+            if (*fmt++ == '%')
+            {
+                  ilen = *fmt++ - '0';
+                  if (ilen == 0)                /* zero means string arg */
+                  {
+                        sval = va_arg(vp, char*);
+                        while (*sval)
+                              *str++ = *sval++;
+                  }
+                  else                          /* always leading zeros */
+                  {
+                        ival = va_arg(vp, int);
+                        while (ilen)
+                        {
+                              ival %= powers[ilen--];
+                              *str++ = (char)('0' + ival / powers[ilen]);
+                        }
+                  }
+            }
+            else  *str++ = fmt[-1];
+      }
+      *str = '\0';
+      va_end(vp);
+}
+
+#ifdef TEST
+
+#include <stdio.h>      /* for printf */
+#include <time.h>       /* for strftime */
+
+char test[80];
+
+int main(int argc, char *argv[])
+{
+      int len;
+      char *fmt;
+      time_t now;
+
+      time(&now);
+
+      fmt = (argc == 1) ? "%I:%M %p\n%c\n" : argv[1];
+      len = strftime_(test,sizeof test, fmt, localtime(&now));
+      printf("%d: %s\n", len, test);
+      return !len;
+}
+
+#endif /* TEST */
diff --git a/src/strftime.h b/src/strftime.h
new file mode 100644 (file)
index 0000000..c9d45e3
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+**  STRFTIME.H - For older compilers which lack strftime()
+**
+**  Note: To avoid name collision with newer compilers, the function name
+**         strftime_() is used.
+*/
+
+#ifndef STRFTIME__H
+#define STRFTIME__H
+
+#include <stddef.h>     /* for size_t */
+#include <time.h>       /* for struct tm */
+
+size_t strftime_(char *s, size_t maxs, const char *f, const struct tm *t);
+
+#if defined(TZNAME_STD) && defined(TZNAME_DST)
+extern char * tzname_[2];
+#endif
+
+#endif /* STRFTIME__H */
diff --git a/src/unused.h b/src/unused.h
new file mode 100644 (file)
index 0000000..b5ac841
--- /dev/null
@@ -0,0 +1,11 @@
+/* define a macro to wrap variables in that would
+   otherwhise generate UNUSED variable warnings */
+
+#ifdef UNUSED
+#elif defined(__GNUC__)
+# define UNUSED(x) x __attribute__((unused))
+#elif defined(__LCLINT__)
+# define UNUSED(x) /*@unused@*/ x
+#else
+# define UNUSED(x) x
+#endif
diff --git a/src/win32comp.c b/src/win32comp.c
new file mode 100644 (file)
index 0000000..32f5337
--- /dev/null
@@ -0,0 +1,67 @@
+// compatibility routines, non reentrant ....
+
+#include <string.h> 
+#include <time.h>
+
+struct tm* localtime_r(const time_t* t, struct tm* r) {
+  struct tm * temp;
+  temp = localtime(t);
+  memcpy(r,temp,sizeof(struct tm));
+  return(r);
+}
+
+struct tm* gmtime_r(const time_t* t, struct tm* r) {
+  struct tm * temp;
+  temp = gmtime(t);
+  memcpy(r,temp,sizeof(struct tm));
+  return r;
+}
+
+char* ctime_r (const time_t* t, char* buf) {
+  char * temp;
+  temp = asctime(localtime(t));
+  strcpy(buf,temp);
+  return(buf);
+}
+
+/*
+       s  
+       Points to the string from which to extract tokens. 
+
+       delim  
+       Points to a null-terminated set of delimiter characters. 
+
+       save_ptr
+       Is a value-return parameter used by strtok_r() to record its progress through s1. 
+*/
+
+
+char * strtok_r (char *s, const char *delim, char **save_ptr) {
+  char *token;
+
+  if (s == NULL)  s = *save_ptr;
+
+  /* Scan leading delimiters.  */
+  s += strspn(s, delim);
+  if (*s == '\0')
+    {
+      *save_ptr = s;
+      return NULL;
+    }
+
+  /* Find the end of the token.  */
+  token = s;
+  s = strpbrk (token, delim);
+  if (s == NULL) {
+    /* This token finishes the string.  */
+         *save_ptr = token;
+         while (**save_ptr != '\0') (*save_ptr)++;
+  }  else
+    {
+      /* Terminate the token and make *SAVE_PTR point past it.  */
+      *s = '\0';
+      *save_ptr = s + 1;
+    }
+  return token;
+}
+
diff --git a/win32/Makefile b/win32/Makefile
new file mode 100644 (file)
index 0000000..8c392d5
--- /dev/null
@@ -0,0 +1,460 @@
+# Gnu Makefile for Win32 target
+# for use with MingW32 gcc or Metrowerks CodeWarrior compiler
+# use with: make -f Makefile [help|all|clean|dev|devclean|dist|distclean]
+#
+# $id: $
+#
+
+DESCR  = Round Robin Database Tool
+COPYR  = Copyright (c) 1997-2007 by Tobias Oetiker
+WWWURL = http://www.rrdtool.org/
+ICON   = $(PROOT)/favicon.ico
+
+# You can set the default font used in graphs.
+# If not set here RRD defaults to DejaVuSansMono-Roman.ttf
+#RRD_DEFAULT_FONT = "arial.ttf"
+#RRD_DEFAULT_FONT = "VeraMono.ttf"
+
+# Vertical label angle: 90.0 (default) or 270.0
+RRDGRAPH_YLEGEND_ANGLE = 90.0
+
+# Set to one if you want to have piecharts.
+WITH_PIECHART = 0
+
+# Set the extension used for rrdcgi.
+ifndef CGIEXT
+CGIEXT = exe
+endif
+
+# Base for the lib sources
+ifndef LIBBASE
+LIBBASE        = ../..
+endif
+# All library code is statically linked to avoid problems with other lib DLLs.
+# Edit the path below to point to your libpng sources or set environment var.
+ifndef LIBPNG
+LIBPNG = $(LIBBASE)/libpng-1.2.16
+endif
+# Edit the path below to point to your freetype sources or set environment var.
+ifndef LIBFT2
+#LIBFT2        = $(LIBBASE)/freetype-2.3.4
+LIBFT2 = $(LIBBASE)/../mingw32/freetype-2.3.4
+endif
+# Edit the path below to point to your libart sources or set environment var.
+ifndef LIBART
+LIBART = $(LIBBASE)/libart_lgpl-2.3.17
+endif
+# Edit the path below to point to your zlib sources or set environment var.
+ifndef ZLIBSDK
+ZLIBSDK        = $(LIBBASE)/zlib-1.2.3
+endif
+
+# Edit the path below to point to your distribution folder.
+ifndef DISTDIR
+DISTDIR        = rrdtool-$(RRD_VERSION_STR)-w32
+endif
+DISTARC = $(DISTDIR).zip
+
+# Edit the path below to point to your distribution folder.
+ifndef DEVLDIR
+DEVLDIR        = rrdtool-$(RRD_VERSION_STR)-sdk-w32
+endif
+DEVLARC = $(DEVLDIR).zip
+
+# whatever...
+NO_NULL_REALLOC = 1
+
+# The following line defines your compiler.
+ifdef METROWERKS
+       CC = mwcc
+else
+       CC = gcc
+endif
+# RM   = rm -f
+CP     = cp -afv
+# Here you can find a native Win32 binary of the original awk:
+# http://www.gknw.net/development/prgtools/awk.zip
+AWK    = awk
+ZIP    = zip -qzr9
+
+# must be equal to DEBUG or NDEBUG
+DB     = NDEBUG
+# DB   = DEBUG
+# Optimization: -O<n> or debugging: -g
+ifeq ($(DB),NDEBUG)
+       OPT     = -O2
+       OBJDIR  = release
+else
+       OPT     = -g
+       OBJDIR  = debug
+endif
+
+# Project root
+PROOT  = ..
+
+# Include the version info retrieved from source.
+-include $(OBJDIR)/version.inc
+
+# Global flags for all compilers
+CFLAGS = $(OPT) -D$(DB) -DHAVE_CONFIG_H
+
+ifeq ($(CC),mwcc)
+LD     = mwld
+RC     = mwwinrc
+LDFLAGS        = -nostdlib
+AR     = $(LD)
+ARFLAGS        = -type library -w nocmdline $(OBJS) -o
+LIBEXT = lib
+LIBPATH        += -lr "$(METROWERKS)/MSL" -lr "$(METROWERKS)/Win32-x86 Support"
+LDLIBS += -lkernel32.lib -luser32.lib
+LDLIBS += -lMSL_Runtime_x86.lib -lMSL_C_x86.lib -lMSL_Extras_x86.lib
+RCFLAGS        =
+CFLAGS += -DWIN32
+CFLAGS += -nostdinc -gccinc -msgstyle gcc -inline off -opt nointrinsics -proc 586
+CFLAGS += -ir "$(METROWERKS)/MSL" -ir "$(METROWERKS)/Win32-x86 Support"
+CFLAGS += -w on,nounused,nounusedexpr # -ansi strict
+else
+LD     = gcc
+RC     = windres
+LDFLAGS        = -s
+AR     = ar
+ARFLAGS        = -cq
+LIBEXT = a
+RCFLAGS        = -O coff -i
+CFLAGS += -fno-strict-aliasing
+CFLAGS += -Wall -Wno-unused # -pedantic
+endif
+
+ifeq ($(findstring msys,$(OSTYPE)),msys)
+DL     = '
+DS     = /
+else
+DS     = \\
+endif
+
+ifndef DESCR
+       DESCR = $(notdir $(@:.rc=)) Command Extension
+endif
+DESCR += - $(CC) build
+
+INCLUDES += -I$(PROOT) -I$(PROOT)/src -I$(LIBPNG) -I$(LIBFT2)/include -I$(LIBART) -I$(ZLIBSDK)
+
+CFLAGS += $(INCLUDES)
+
+vpath %.c $(PROOT)/src $(LIBPNG) $(LIBART)/libart_lgpl $(ZLIBSDK)
+
+RRDLIBOBJS     = \
+       $(OBJDIR)/rrd_afm.o \
+       $(OBJDIR)/rrd_afm_data.o \
+       $(OBJDIR)/rrd_create.o \
+       $(OBJDIR)/rrd_diff.o \
+       $(OBJDIR)/rrd_dump.o \
+       $(OBJDIR)/rrd_error.o \
+       $(OBJDIR)/rrd_fetch.o \
+       $(OBJDIR)/rrd_first.o \
+       $(OBJDIR)/rrd_format.o \
+       $(OBJDIR)/rrd_gfx.o \
+       $(OBJDIR)/rrd_graph.o \
+       $(OBJDIR)/rrd_graph_helper.o \
+       $(OBJDIR)/rrd_hw.o \
+       $(OBJDIR)/rrd_info.o \
+       $(OBJDIR)/rrd_last.o \
+       $(OBJDIR)/rrd_lastupdate.o \
+       $(OBJDIR)/rrd_nan_inf.o \
+       $(OBJDIR)/rrd_open.o \
+       $(OBJDIR)/rrd_resize.o \
+       $(OBJDIR)/rrd_restore.o \
+       $(OBJDIR)/rrd_rpncalc.o \
+       $(OBJDIR)/rrd_tune.o \
+       $(OBJDIR)/rrd_update.o \
+       $(OBJDIR)/rrd_version.o \
+       $(OBJDIR)/rrd_xport.o \
+       $(OBJDIR)/rrd_thread_safe_nt.o \
+       $(EOLIST)
+
+XLIBOBJS       = \
+       $(OBJDIR)/rrd_getopt.o \
+       $(OBJDIR)/rrd_getopt1.o \
+       $(OBJDIR)/art_rgba_svp.o \
+       $(OBJDIR)/hash_32.o \
+       $(OBJDIR)/parsetime.o \
+       $(OBJDIR)/pngsize.o \
+       $(OBJDIR)/strftime.o \
+       $(EOLIST)
+
+PNGLIBOBJS     = \
+       $(OBJDIR)/png.o \
+       $(OBJDIR)/pngerror.o \
+       $(OBJDIR)/pngget.o \
+       $(OBJDIR)/pngmem.o \
+       $(OBJDIR)/pngpread.o \
+       $(OBJDIR)/pngread.o \
+       $(OBJDIR)/pngrio.o \
+       $(OBJDIR)/pngrtran.o \
+       $(OBJDIR)/pngrutil.o \
+       $(OBJDIR)/pngset.o \
+       $(OBJDIR)/pngtrans.o \
+       $(OBJDIR)/pngwio.o \
+       $(OBJDIR)/pngwrite.o \
+       $(OBJDIR)/pngwtran.o \
+       $(OBJDIR)/pngwutil.o \
+       $(EOLIST)
+ifeq "$(wildcard $(LIBPNG)/pnggccrd.c)" "$(LIBPNG)/pnggccrd.c"
+PNGLIBOBJS     += \
+       $(OBJDIR)/pnggccrd.o \
+       $(OBJDIR)/pngvcrd.o \
+       $(EOLIST)
+endif
+
+ZLIBOBJS       = \
+       $(OBJDIR)/adler32.o \
+       $(OBJDIR)/compress.o \
+       $(OBJDIR)/crc32.o \
+       $(OBJDIR)/deflate.o \
+       $(OBJDIR)/inflate.o \
+       $(OBJDIR)/inffast.o \
+       $(OBJDIR)/inftrees.o \
+       $(OBJDIR)/trees.o \
+       $(OBJDIR)/zutil.o \
+       $(EOLIST)
+ifeq "$(wildcard $(ZLIBSDK)/infblock.c)" "$(ZLIBSDK)/infblock.c"
+ZLIBOBJS       += \
+       $(OBJDIR)/infblock.o \
+       $(OBJDIR)/infcodes.o \
+       $(OBJDIR)/infutil.o \
+       $(EOLIST)
+endif
+
+ARTLIBOBJS     = \
+       $(patsubst $(LIBART)/libart_lgpl/%.c,$(OBJDIR)/%.o,$(wildcard $(LIBART)/libart_lgpl/art_*.c))
+
+OBJS   := $(RRDLIBOBJS) $(XLIBOBJS) $(PNGLIBOBJS) $(ARTLIBOBJS) $(ZLIBOBJS)
+OBJCGI := $(OBJS) $(OBJDIR)/rrd_cgi.o
+OBJTOOL        := $(OBJS) $(OBJDIR)/rrd_tool.o
+
+LDLIBS += $(LIBFT2)/objs/freetype.$(LIBEXT)
+
+
+all: rrdtool rrdcgi
+
+rrdtool: $(OBJDIR) $(PROOT)/rrd_config.h $(OBJDIR)/rrdtool.exe
+rrdcgi: $(OBJDIR) $(PROOT)/rrd_config.h $(OBJDIR)/rrdcgi.$(CGIEXT)
+librrd: $(OBJDIR) $(PROOT)/rrd_config.h $(OBJDIR)/librrd.$(LIBEXT)
+
+FORCE: ;
+
+dist: all $(DISTDIR) $(DISTDIR)/readme.txt
+       @-$(CP) $(OBJDIR)/rrdcgi.$(CGIEXT) $(DISTDIR)
+       @-$(CP) $(OBJDIR)/rrdtool.exe $(DISTDIR)
+       @-$(CP) $(PROOT)/src/*.ttf $(DISTDIR)
+       @-$(CP) $(PROOT)/CHANGES $(DISTDIR)
+       @-$(CP) $(PROOT)/COPYING $(DISTDIR)
+       @-$(CP) $(PROOT)/COPYRIGHT $(DISTDIR)
+       @-$(CP) $(PROOT)/NEWS $(DISTDIR)
+       @-$(CP) $(PROOT)/README $(DISTDIR)
+       @echo Creating $(DISTARC)
+       @$(ZIP) $(DISTARC) $(DISTDIR)/* < $(DISTDIR)/readme.txt
+
+dev: librrd $(DEVLDIR) $(DEVLDIR)/readme.txt
+       @-mkdir $(DEVLDIR)$(DS)include
+       @-mkdir $(DEVLDIR)$(DS)lib
+       @-mkdir $(DEVLDIR)$(DS)src
+       @-$(CP) $(OBJDIR)/librrd.$(LIBEXT) $(DEVLDIR)/lib
+       @-$(CP) $(PROOT)/rrd_config.h $(DEVLDIR)/include
+       @-$(CP) $(PROOT)/src/rrd.h $(DEVLDIR)/include
+       @-$(CP) $(PROOT)/src/*.ttf $(DEVLDIR)/src
+       @-$(CP) $(PROOT)/CHANGES $(DEVLDIR)
+       @-$(CP) $(PROOT)/COPYING $(DEVLDIR)
+       @-$(CP) $(PROOT)/COPYRIGHT $(DEVLDIR)
+       @-$(CP) $(PROOT)/NEWS $(DEVLDIR)
+       @-$(CP) $(PROOT)/README $(DEVLDIR)
+       @echo Creating $(DEVLARC)
+       @$(ZIP) $(DEVLARC) $(DEVLDIR)/* < $(DEVLDIR)/readme.txt
+
+clean:
+       -$(RM) -r $(OBJDIR)
+       -$(RM) $(PROOT)/rrd_config.h
+
+distclean: clean
+       -$(RM) -r $(DISTDIR)
+       -$(RM) $(DISTARC)
+
+devclean: clean
+       -$(RM) -r $(DEVLDIR)
+       -$(RM) $(DEVLARC)
+
+$(OBJDIR):
+       @mkdir $@
+
+$(DISTDIR):
+       @mkdir $@
+
+$(DEVLDIR):
+       @mkdir $@
+
+$(OBJDIR)/version.inc: $(PROOT)/configure.ac $(OBJDIR) $(PROOT)/src/get_ver.awk
+       @echo Creating $@
+       @$(AWK) -f $(PROOT)/src/get_ver.awk $< > $@
+
+$(OBJDIR)/%.o: %.c
+       @echo Compiling $<
+       @$(CC) $(CFLAGS) -c $< -o $@
+
+$(OBJDIR)/rrdcgi.$(CGIEXT): $(OBJCGI) $(OBJDIR)/rrdcgi.res
+       @echo Linking $@
+       @-$(RM) $@
+       @$(LD) $(LDFLAGS) $^ -o $@ $(LIBPATH) $(LDLIBS)
+
+$(OBJDIR)/rrdtool.exe: $(OBJTOOL) $(OBJDIR)/rrdtool.res
+       @echo Linking $@
+       @-$(RM) $@
+       @$(LD) $(LDFLAGS) $^ -o $@ $(LIBPATH) $(LDLIBS)
+
+$(OBJDIR)/librrd.$(LIBEXT): $(OBJS)
+       @echo Creating $@
+       @-$(RM) $@
+       @$(AR) $(ARFLAGS) $@ $^
+
+$(OBJDIR)/%.res: $(OBJDIR)/%.rc
+       @echo Creating $@
+       @$(RC) $(RCFLAGS) $< -o $@
+
+$(OBJDIR)/%.rc: Makefile $(OBJDIR)/version.inc
+       @echo $(DL)1 VERSIONINFO$(DL) > $@
+       @echo $(DL) FILEVERSION $(RRD_VERSION),0$(DL) >> $@
+       @echo $(DL) PRODUCTVERSION $(RRD_VERSION),0$(DL) >> $@
+       @echo $(DL) FILEFLAGSMASK 0x3fL$(DL) >> $@
+       @echo $(DL) FILEOS 0x40004L$(DL) >> $@
+       @echo $(DL) FILEFLAGS 0x0L$(DL) >> $@
+       @echo $(DL) FILETYPE 0x1L$(DL) >> $@
+       @echo $(DL) FILESUBTYPE 0x0L$(DL) >> $@
+       @echo $(DL)BEGIN$(DL) >> $@
+       @echo $(DL)  BLOCK "StringFileInfo"$(DL) >> $@
+       @echo $(DL)  BEGIN$(DL) >> $@
+       @echo $(DL)    BLOCK "040904E4"$(DL) >> $@
+       @echo $(DL)    BEGIN$(DL) >> $@
+       @echo $(DL)      VALUE "LegalCopyright","$(COPYR)\0"$(DL) >> $@
+ifdef COMPANY
+       @echo $(DL)      VALUE "CompanyName","$(COMPANY)\0"$(DL) >> $@
+endif
+       @echo $(DL)      VALUE "ProductName","$(notdir $(@:.rc=.exe))\0"$(DL) >> $@
+       @echo $(DL)      VALUE "ProductVersion","$(RRD_VERSION_STR)\0"$(DL) >> $@
+       @echo $(DL)      VALUE "License","Released under GPL.\0"$(DL) >> $@
+       @echo $(DL)      VALUE "FileDescription","$(DESCR)\0"$(DL) >> $@
+       @echo $(DL)      VALUE "FileVersion","$(RRD_VERSION_STR)\0"$(DL) >> $@
+       @echo $(DL)      VALUE "InternalName","$(notdir $(@:.rc=))\0"$(DL) >> $@
+       @echo $(DL)      VALUE "OriginalFilename","$(notdir $(@:.rc=.exe))\0"$(DL) >> $@
+       @echo $(DL)      VALUE "WWW","$(WWWURL)\0"$(DL) >> $@
+       @echo $(DL)    END$(DL) >> $@
+       @echo $(DL)  END$(DL) >> $@
+       @echo $(DL)  BLOCK "VarFileInfo"$(DL) >> $@
+       @echo $(DL)  BEGIN$(DL) >> $@
+       @echo $(DL)    VALUE "Translation", 0x409, 1252$(DL) >> $@
+       @echo $(DL)  END$(DL) >> $@
+       @echo $(DL)END$(DL) >> $@
+ifdef ICON
+       @echo $(DL)10 ICON DISCARDABLE "$(ICON)"$(DL) >> $@
+endif
+
+$(PROOT)/rrd_config.h: FORCE Makefile $(OBJDIR)/version.inc
+       @echo Creating $@
+       @echo $(DL)/* $(notdir $@) for Win32 target.$(DL) > $@
+       @echo $(DL)** Do not edit this file - it is created by make!$(DL) >> $@
+       @echo $(DL)** All your changes will be lost!!$(DL) >> $@
+       @echo $(DL)*/$(DL) >> $@
+       @echo $(DL)#ifndef WIN32$(DL) >> $@
+       @echo $(DL)#error This $(notdir $@) is created for Win32 platform!$(DL) >> $@
+       @echo $(DL)#endif$(DL) >> $@
+       @echo $(DL)#ifndef RRD_CONFIG_H$(DL) >> $@
+       @echo $(DL)#define RRD_CONFIG_H$(DL) >> $@
+       @echo $(DL)#define OS "i586-pc-Win32"$(DL) >> $@
+       @echo $(DL)#define PACKAGE_VERSION "$(RRD_VERSION_STR)"$(DL) >> $@
+       @echo $(DL)#define PACKAGE_BUGREPORT "tobi@oetiker.ch"$(DL) >> $@
+       @echo $(DL)#define NUMVERS $(RRD_NUMVERS)$(DL) >> $@
+       @echo $(DL)#define HAVE_ASSERT_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_DLFCN_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_DLOPEN 1$(DL) >> $@
+       @echo $(DL)#define HAVE_ERRNO_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_FCNTL_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_FIONBIO 1$(DL) >> $@
+       @echo $(DL)#define HAVE_INTTYPES_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_LIMITS_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_LONGLONG 1$(DL) >> $@
+       @echo $(DL)#define HAVE_LOCALE_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_MALLOC_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_MATH_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_MBSTOWCS 1$(DL) >> $@
+       @echo $(DL)#define HAVE_SETJMP_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_SNPRINTF 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STDARG_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STDDEF_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STDINT_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STDLIB_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STRCASECMP 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STRDUP 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STRFTIME 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STRING_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STRLCAT 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STRLCPY 1$(DL) >> $@
+       @echo $(DL)#define HAVE_STRSTR 1$(DL) >> $@
+       @echo $(DL)#define HAVE_SYS_PARAM_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_SYS_STAT_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_SYS_TIME_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_TIME_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_VSNPRINTF 1$(DL) >> $@
+       @echo $(DL)#define STDC_HEADERS 1$(DL) >> $@
+       @echo $(DL)#define TIME_WITH_SYS_TIME 1$(DL) >> $@
+       @echo $(DL)#define HAVE_ZLIB_H 1$(DL) >> $@
+       @echo $(DL)#define HAVE_LIBZ 1$(DL) >> $@
+ifdef NO_NULL_REALLOC
+       @echo $(DL)#define NO_NULL_REALLOC 1$(DL) >> $@
+       @echo $(DL)#define rrd_realloc(a,b) ( (a) == NULL ? malloc( (b) ) : realloc( (a) , (b) ))$(DL) >> $@
+else
+       @echo $(DL)#define rrd_realloc(a,b) realloc((a), (b))$(DL) >> $@
+endif
+ifdef RRD_DEFAULT_FONT
+       @echo $(DL)#define RRD_DEFAULT_FONT $(RRD_DEFAULT_FONT)$(DL) >> $@
+endif
+       @echo $(DL)#define RRDGRAPH_YLEGEND_ANGLE $(RRDGRAPH_YLEGEND_ANGLE)$(DL) >> $@
+       @echo $(DL)#define strftime strftime_$(DL) >> $@
+ifdef WITH_PIECHART
+       @echo $(DL)#define WITH_PIECHART $(WITH_PIECHART)$(DL) >> $@
+endif
+       @echo $(DL)#endif /* RRD_CONFIG_H */$(DL) >> $@
+
+$(DISTDIR)/readme.txt: Makefile
+       @echo Creating $@
+       @echo $(DL)This is a binary distribution for Win32 platform.$(DL) > $@
+       @echo $(DL)RRDTool version $(RRD_VERSION_STR)$(DL) >> $@
+       @echo $(DL)Please download the complete RRDTool package for$(DL) >> $@
+       @echo $(DL)any further documentation:$(DL) >> $@
+       @echo $(DL)$(WWWURL)$(DL) >> $@
+
+$(DEVLDIR)/readme.txt: Makefile
+       @echo Creating $@
+       @echo $(DL)This is a development distribution for Win32 platform.$(DL) > $@
+       @echo $(DL)RRDTool version $(RRD_VERSION_STR)$(DL) >> $@
+       @echo $(DL)Please download the complete RRDTool package for$(DL) >> $@
+       @echo $(DL)any further documentation:$(DL) >> $@
+       @echo $(DL)$(WWWURL)$(DL) >> $@
+
+help:
+       @echo $(DL)===========================================================$(DL)
+       @echo $(DL)libpng Source   = $(LIBPNG)$(DL)
+       @echo $(DL)libart Source   = $(LIBART)$(DL)
+       @echo $(DL)Freetype 2 SDK  = $(LIBFT2)$(DL)
+       @echo $(DL)Zlib SDK        = $(ZLIBSDK)$(DL)
+       @echo $(DL)===========================================================$(DL)
+       @echo $(DL)RRDTool $(RRD_VERSION_STR) - available targets are:$(DL)
+       @echo $(DL)$(MAKE) all$(DL)
+       @echo $(DL)$(MAKE) rrdtool$(DL)
+       @echo $(DL)$(MAKE) rrdcgi$(DL)
+       @echo $(DL)$(MAKE) librrd$(DL)
+       @echo $(DL)$(MAKE) clean$(DL)
+       @echo $(DL)$(MAKE) dev$(DL)
+       @echo $(DL)$(MAKE) devclean$(DL)
+       @echo $(DL)$(MAKE) dist$(DL)
+       @echo $(DL)$(MAKE) distclean$(DL)
+       @echo $(DL)===========================================================$(DL)
+
+
diff --git a/win32/config.h b/win32/config.h
new file mode 100644 (file)
index 0000000..965d525
--- /dev/null
@@ -0,0 +1,60 @@
+/* config.h.msvc.  Hand-tweaked config.h for MSVC compiler.  */
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#include <math.h>
+#include <float.h>
+#include <direct.h>
+
+/* realloc does not support NULL as argument */
+
+#define HAVE_STRFTIME 1
+#define HAVE_TIME_H 1
+#define HAVE_LOCALE_H 1
+#define HAVE_TZSET 1
+#define HAVE_SETLOCALE 1
+#define HAVE_MATH_H 1
+#define HAVE_FLOAT_H 1
+#define HAVE_MEMMOVE 1
+#define HAVE_MALLOC_H 1
+#define HAVE_MKTIME 1
+#define HAVE_STRFTIME 1
+#define HAVE_STRING_H 1
+#define HAVE_VSNPRINTF 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+#define NUMVERS 1.2015
+#define PACKAGE_NAME "rrdtool"
+#define PACKAGE_VERSION "1.2.15"
+#define PACKAGE_STRING PACKAGE_NAME " " PACKAGE_VERSION
+
+#define isinf(a) (_fpclass(a) == _FPCLASS_NINF || _fpclass(a) == _FPCLASS_PINF)
+#define isnan _isnan
+#define finite _finite
+#define snprintf _snprintf
+#define vsnprintf _vsnprintf
+#define strftime strftime_ 
+
+#define NO_NULL_REALLOC 1
+#if NO_NULL_REALLOC
+# define rrd_realloc(a,b) ( (a) == NULL ? malloc( (b) ) : realloc( (a) , (b) ))
+#else
+# define rrd_realloc(a,b) realloc((a), (b))
+#endif      
+
+/* Vertical label angle: 90.0 (default) or 270.0 */
+#define RRDGRAPH_YLEGEND_ANGLE 90.0
+
+#define RRD_DEFAULT_FONT "arial.ttf"
+/* #define RRD_DEFAULT_FONT "DejaVuSansMono-Roman.ttf" */
+
+/* #define WITH_PIECHART 1 */
+
+/* #define DEBUG 1 */
+
+#endif /* CONFIG_H */
+
diff --git a/win32/rrd.dsp b/win32/rrd.dsp
new file mode 100644 (file)
index 0000000..fbc0c1d
--- /dev/null
@@ -0,0 +1,247 @@
+# Microsoft Developer Studio Project File - Name="rrd" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
+\r
+CFG=rrd - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "rrd.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "rrd.mak" CFG="rrd - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "rrd - Win32 Release" (based on "Win32 (x86) Static Library")\r
+!MESSAGE "rrd - Win32 Debug" (based on "Win32 (x86) Static Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "rrd - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "rrd___Wi"\r
+# PROP BASE Intermediate_Dir "rrd___Wi"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "release"\r
+# PROP Intermediate_Dir "release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /I "../src" /I "../../zlib-1.2.3" /I "../../libpng-1.2.16" /I "../../libart_lgpl-2.3.17" /I "../../freetype-2.3.1/include" /D "HAVE_CONFIG_H" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_CTYPE_DISABLE_MACROS" /FD /c\r
+# SUBTRACT CPP /X /YX\r
+# ADD BASE RSC /l 0x100c\r
+# ADD RSC /l 0x409\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo\r
+\r
+!ELSEIF  "$(CFG)" == "rrd - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "rrd___W0"\r
+# PROP BASE Intermediate_Dir "rrd___W0"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "debug"\r
+# PROP Intermediate_Dir "debug"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c\r
+# ADD CPP /nologo /MD /W3 /Gm /GX /ZI /Od /I "../src" /I "../../zlib-1.2.3" /I "../../libpng-1.2.16" /I "../../libart_lgpl-2.3.17" /I "../../freetype-2.3.1/include" /D "HAVE_CONFIG_H" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "_CTYPE_DISABLE_MACROS" /FR /FD /c\r
+# SUBTRACT CPP /X /YX\r
+# ADD BASE RSC /l 0x100c\r
+# ADD RSC /l 0x409\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo /o"rrd.bsc"\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "rrd - Win32 Release"\r
+# Name "rrd - Win32 Debug"\r
+# Begin Source File\r
+\r
+SOURCE="..\src\get_ver.awk"\r
+\r
+!IF  "$(CFG)" == "rrd - Win32 Release"\r
+\r
+# PROP Ignore_Default_Tool 1\r
+# Begin Custom Build - Creating ..\rrd_config.h\r
+InputPath="..\src\get_ver.awk"\r
+\r
+"..\rrd_config.h" : $(SOURCE) "..\configure.ac" "..\win32\rrd_config.h.msvc"\r
+       awk -f ..\src\get_ver.awk ..\configure.ac ..\win32\rrd_config.h.msvc > ..\rrd_config.h\r
+\r
+# End Custom Build\r
+\r
+!ELSEIF  "$(CFG)" == "rrd - Win32 Debug"\r
+\r
+# PROP Ignore_Default_Tool 1\r
+# Begin Custom Build - Creating ..\rrd_config.h\r
+InputPath="..\src\get_ver.awk"\r
+\r
+"..\rrd_config.h" : $(SOURCE) "..\configure.ac" "..\win32\rrd_config.h.msvc"\r
+       awk -f ..\src\get_ver.awk ..\configure.ac ..\win32\rrd_config.h.msvc > ..\rrd_config.h\r
+\r
+# End Custom Build\r
+\r
+!ENDIF\r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_afm.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_afm_data.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_create.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_diff.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_dump.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_error.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_fetch.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_first.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_format.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_gfx.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_graph.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_graph_helper.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_hw.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_info.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_last.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_lastupdate.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_nan_inf.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_open.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_resize.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_restore.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_rpncalc.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_thread_safe_nt.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_tune.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_update.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_version.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_xport.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_getopt.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_getopt1.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\art_rgba_svp.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\hash_32.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\parsetime.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\pngsize.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\src\strftime.c\r
+# End Source File\r
+# End Target\r
+# End Project\r
diff --git a/win32/rrd.vcproj b/win32/rrd.vcproj
new file mode 100644 (file)
index 0000000..30ca966
--- /dev/null
@@ -0,0 +1,648 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="7.10"\r
+       Name="rrd"\r
+       SccProjectName=""\r
+       SccLocalPath="">\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"/>\r
+       </Platforms>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory=".\release"\r
+                       IntermediateDirectory=".\release"\r
+                       ConfigurationType="4"\r
+                       UseOfMFC="0"\r
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="4"\r
+                               AdditionalIncludeDirectories="\Program Files\GnuWin32\include,\Program Files\GnuWin32\include\freetype2"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_CTYPE_DISABLE_MACROS"\r
+                               RuntimeLibrary="2"\r
+                               PrecompiledHeaderFile=".\release/rrd.pch"\r
+                               AssemblerListingLocation=".\release/"\r
+                               ObjectFile=".\release/"\r
+                               ProgramDataBaseFileName=".\release/"\r
+                               WarningLevel="3"\r
+                               SuppressStartupBanner="TRUE"\r
+                               CompileAs="0"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                               OutputFile=".\release\rrd.lib"\r
+                               SuppressStartupBanner="TRUE"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               Culture="4108"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCManagedWrapperGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory=".\debug"\r
+                       IntermediateDirectory=".\debug"\r
+                       ConfigurationType="4"\r
+                       UseOfMFC="0"\r
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="\Program Files\GnuWin32\include\freetype2,\Program Files\GnuWin32\include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CTYPE_DISABLE_MACROS"\r
+                               RuntimeLibrary="2"\r
+                               PrecompiledHeaderFile=".\debug/rrd.pch"\r
+                               AssemblerListingLocation=".\debug/"\r
+                               ObjectFile=".\debug/"\r
+                               ProgramDataBaseFileName=".\debug/"\r
+                               BrowseInformation="1"\r
+                               WarningLevel="3"\r
+                               SuppressStartupBanner="TRUE"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                               OutputFile=".\debug\rrd.lib"\r
+                               SuppressStartupBanner="TRUE"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               Culture="4108"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCManagedWrapperGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <File\r
+                       RelativePath="getopt.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="getopt1.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="hash_32.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="parsetime.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="pngsize.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_afm.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_afm_data.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_create.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_diff.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_dump.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_error.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_fetch.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_format.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_gfx.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_graph.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_graph_helper.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_hw.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_info.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_last.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_nan_inf.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_open.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_resize.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_restore.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_rpncalc.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_thread_safe_nt.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_tune.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_update.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+               <File\r
+                       RelativePath="rrd_xport.c">\r
+                       <FileConfiguration\r
+                               Name="Release|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""/>\r
+                       </FileConfiguration>\r
+                       <FileConfiguration\r
+                               Name="Debug|Win32">\r
+                               <Tool\r
+                                       Name="VCCLCompilerTool"\r
+                                       Optimization="0"\r
+                                       AdditionalIncludeDirectories=""\r
+                                       PreprocessorDefinitions=""\r
+                                       BrowseInformation="1"/>\r
+                       </FileConfiguration>\r
+               </File>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/win32/rrd_config.h.msvc b/win32/rrd_config.h.msvc
new file mode 100644 (file)
index 0000000..8a83923
--- /dev/null
@@ -0,0 +1,65 @@
+/* rrd_config.h.msvc. Hand-tweaked rrd_config.h for MSVC compiler. */\r
+#ifndef WIN32 \r
+#error This rrd_config.h is created for Win32 platform! \r
+#endif \r
+#ifndef RRD_CONFIG_H\r
+#define RRD_CONFIG_H\r
+\r
+#include <math.h>\r
+#include <float.h>\r
+#include <direct.h>\r
+\r
+/* the placeholders will be filled in by get_ver.awk */\r
+/* http://cm.bell-labs.com/cm/cs/awkbook/index.html */\r
+#define NUMVERS @@NUMVERS@@\r
+#define PACKAGE_VERSION "@@PACKAGE_VERSION@@"\r
+\r
+#define PACKAGE_NAME "rrdtool"\r
+#define PACKAGE_STRING PACKAGE_NAME " " PACKAGE_VERSION\r
+\r
+#define HAVE_STRFTIME 1\r
+#define HAVE_TIME_H 1\r
+#define HAVE_LOCALE_H 1\r
+#define HAVE_TZSET 1\r
+#define HAVE_SETLOCALE 1\r
+#define HAVE_MATH_H 1\r
+#define HAVE_FLOAT_H 1\r
+#define HAVE_MEMMOVE 1\r
+#define HAVE_MALLOC_H 1\r
+#define HAVE_MKTIME 1\r
+#define HAVE_STRFTIME 1\r
+#define HAVE_STRING_H 1\r
+#define HAVE_VSNPRINTF 1\r
+#define HAVE_SYS_TYPES_H 1\r
+#define HAVE_SYS_STAT_H 1\r
+\r
+/* Define to 1 if you have the ANSI C header files. */\r
+#define STDC_HEADERS 1\r
+\r
+#define isinf(a) (_fpclass(a) == _FPCLASS_NINF || _fpclass(a) == _FPCLASS_PINF)\r
+#define isnan _isnan\r
+#define finite _finite\r
+#define snprintf _snprintf\r
+#define vsnprintf _vsnprintf\r
+#define strftime strftime_ \r
+\r
+/* realloc does not support NULL as argument */\r
+#define NO_NULL_REALLOC 1\r
+#if NO_NULL_REALLOC\r
+# define rrd_realloc(a,b) ( (a) == NULL ? malloc( (b) ) : realloc( (a) , (b) ))\r
+#else\r
+# define rrd_realloc(a,b) realloc((a), (b))\r
+#endif      \r
+\r
+/* Vertical label angle: 90.0 (default) or 270.0 */\r
+#define RRDGRAPH_YLEGEND_ANGLE 90.0\r
+\r
+#define RRD_DEFAULT_FONT "arial.ttf"\r
+/* #define RRD_DEFAULT_FONT "DejaVuSansMono-Roman.ttf" */\r
+\r
+/* #define WITH_PIECHART 1 */\r
+\r
+/* #define DEBUG 1 */\r
+\r
+#endif /* RRD_CONFIG_H */\r
+\r
diff --git a/win32/rrdtool.dsp b/win32/rrdtool.dsp
new file mode 100644 (file)
index 0000000..1a192fe
--- /dev/null
@@ -0,0 +1,92 @@
+# Microsoft Developer Studio Project File - Name="rrdtool" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=rrdtool - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "rrdtool.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "rrdtool.mak" CFG="rrdtool - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "rrdtool - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "rrdtool - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "rrdtool - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "rrdtool_"\r
+# PROP BASE Intermediate_Dir "rrdtool_"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "toolrelease"\r
+# PROP Intermediate_Dir "toolrelease"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /I "../src" /I "../../zlib-1.2.3" /I "../../libpng-1.2.16" /I "../../libart_lgpl-2.3.17" /I "../../freetype-2.3.1/include" /D "HAVE_CONFIG_H" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_CTYPE_DISABLE_MACROS" /FD /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x100c /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 libpng.lib zlib.lib libart.lib freetype231MT.lib kernel32.lib user32.lib /nologo /subsystem:console /incremental:yes /debug /machine:I386 /libpath:"../../libpng-1.2.16/projects/visualc6/Win32_LIB_Release" /libpath:"../../zlib-1.2.3" /libpath:"../../libart_lgpl-2.3.17/win32/release" /libpath:"../../freetype-2.3.1/objs"\r
+\r
+!ELSEIF  "$(CFG)" == "rrdtool - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "rrdtool0"\r
+# PROP BASE Intermediate_Dir "rrdtool0"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "tooldebug"\r
+# PROP Intermediate_Dir "tooldebug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /MD /W3 /Gm /GX /ZI /Od /I "../src" /I "../../zlib-1.2.3" /I "../../libpng-1.2.16" /I "../../libart_lgpl-2.3.17" /I "../../freetype-2.3.1/include" /D "HAVE_CONFIG_H" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "_CTYPE_DISABLE_MACROS" /FR /FD /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x100c /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo /o"rrdtool.bsc"\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 libpng.lib zlib.lib libart.lib freetype231MT.lib kernel32.lib user32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"../../libpng-1.2.16/projects/visualc6/Win32_LIB_Release" /libpath:"../../zlib-1.2.3" /libpath:"../../libart_lgpl-2.3.17/win32/release" /libpath:"../../freetype-2.3.1/objs"\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "rrdtool - Win32 Release"\r
+# Name "rrdtool - Win32 Debug"\r
+# Begin Source File\r
+\r
+SOURCE=..\src\rrd_tool.c\r
+# End Source File\r
+# End Target\r
+# End Project\r
diff --git a/win32/rrdtool.dsw b/win32/rrdtool.dsw
new file mode 100644 (file)
index 0000000..07103ba
--- /dev/null
@@ -0,0 +1,44 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00\r
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r
+\r
+###############################################################################\r
+\r
+Project: "rrd"=".\rrd.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "rrdtool"=".\rrdtool.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name rrd\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Global:\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<3>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
diff --git a/win32/rrdtool.vcproj b/win32/rrdtool.vcproj
new file mode 100644 (file)
index 0000000..7ba111a
--- /dev/null
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="7.10"
+       Name="rrdtool"
+       SccProjectName=""
+       SccLocalPath="">
+       <Platforms>
+               <Platform
+                       Name="Win32"/>
+       </Platforms>
+       <Configurations>
+               <Configuration
+                       Name="Release|Win32"
+                       OutputDirectory=".\toolrelease"
+                       IntermediateDirectory=".\toolrelease"
+                       ConfigurationType="1"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"
+                       CharacterSet="2">
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="4"
+                               AdditionalIncludeDirectories="\Program Files\GnuWin32\include,\Program Files\GnuWin32\include\freetype2"
+                               PreprocessorDefinitions="NDEBUG;_WINDOWS;WIN32;_CTYPE_DISABLE_MACROS"
+                               RuntimeLibrary="2"
+                               PrecompiledHeaderFile=".\toolrelease/rrdtool.pch"
+                               AssemblerListingLocation=".\toolrelease/"
+                               ObjectFile=".\toolrelease/"
+                               ProgramDataBaseFileName=".\toolrelease/"
+                               WarningLevel="3"
+                               SuppressStartupBanner="TRUE"
+                               CompileAs="0"/>
+                       <Tool
+                               Name="VCCustomBuildTool"/>
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="libpng.lib libz.lib libart_lgpl.lib libfreetype.lib"
+                               OutputFile=".\toolrelease/rrdtool.exe"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="TRUE"
+                               AdditionalLibraryDirectories="\Program Files\GnuWin32\lib"
+                               GenerateDebugInformation="TRUE"
+                               ProgramDatabaseFile=".\toolrelease/rrdtool.pdb"
+                               SubSystem="1"
+                               TargetMachine="1"/>
+                       <Tool
+                               Name="VCMIDLTool"
+                               TypeLibraryName=".\toolrelease/rrdtool.tlb"
+                               HeaderFileName=""/>
+                       <Tool
+                               Name="VCPostBuildEventTool"/>
+                       <Tool
+                               Name="VCPreBuildEventTool"/>
+                       <Tool
+                               Name="VCPreLinkEventTool"/>
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               Culture="4108"/>
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"/>
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"/>
+                       <Tool
+                               Name="VCWebDeploymentTool"/>
+                       <Tool
+                               Name="VCManagedWrapperGeneratorTool"/>
+                       <Tool
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+               </Configuration>
+               <Configuration
+                       Name="Debug|Win32"
+                       OutputDirectory=".\tooldebug"
+                       IntermediateDirectory=".\tooldebug"
+                       ConfigurationType="1"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"
+                       CharacterSet="2">
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="0"
+                               AdditionalIncludeDirectories="\Program Files\GnuWin32\include\freetype2,\Program Files\GnuWin32\include"
+                               PreprocessorDefinitions="_DEBUG;_CONSOLE;WIN32;_CTYPE_DISABLE_MACROS"
+                               RuntimeLibrary="2"
+                               PrecompiledHeaderFile=".\tooldebug/rrdtool.pch"
+                               AssemblerListingLocation=".\tooldebug/"
+                               ObjectFile=".\tooldebug/"
+                               ProgramDataBaseFileName=".\tooldebug/"
+                               BrowseInformation="1"
+                               WarningLevel="3"
+                               SuppressStartupBanner="TRUE"
+                               DebugInformationFormat="4"
+                               CompileAs="0"/>
+                       <Tool
+                               Name="VCCustomBuildTool"/>
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="libpng.lib libz.lib libart_lgpl.lib libfreetype.lib"
+                               OutputFile=".\tooldebug/rrdtool.exe"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="TRUE"
+                               AdditionalLibraryDirectories="\Program Files\GnuWin32\lib"
+                               GenerateDebugInformation="TRUE"
+                               ProgramDatabaseFile=".\tooldebug/rrdtool.pdb"
+                               SubSystem="1"
+                               TargetMachine="1"/>
+                       <Tool
+                               Name="VCMIDLTool"
+                               TypeLibraryName=".\tooldebug/rrdtool.tlb"
+                               HeaderFileName=""/>
+                       <Tool
+                               Name="VCPostBuildEventTool"/>
+                       <Tool
+                               Name="VCPreBuildEventTool"/>
+                       <Tool
+                               Name="VCPreLinkEventTool"/>
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               Culture="4108"/>
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"/>
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"/>
+                       <Tool
+                               Name="VCWebDeploymentTool"/>
+                       <Tool
+                               Name="VCManagedWrapperGeneratorTool"/>
+                       <Tool
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <File
+                       RelativePath="rrd_tool.c">
+                       <FileConfiguration
+                               Name="Release|Win32">
+                               <Tool
+                                       Name="VCCLCompilerTool"
+                                       AdditionalIncludeDirectories=""
+                                       PreprocessorDefinitions=""/>
+                       </FileConfiguration>
+                       <FileConfiguration
+                               Name="Debug|Win32">
+                               <Tool
+                                       Name="VCCLCompilerTool"
+                                       Optimization="0"
+                                       AdditionalIncludeDirectories=""
+                                       PreprocessorDefinitions=""
+                                       BrowseInformation="1"/>
+                       </FileConfiguration>
+               </File>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>