Installed eximstats 1.33
authorPhilip Hazel <ph10@hermes.cam.ac.uk>
Wed, 24 Nov 2004 14:43:57 +0000 (14:43 +0000)
committerPhilip Hazel <ph10@hermes.cam.ac.uk>
Wed, 24 Nov 2004 14:43:57 +0000 (14:43 +0000)
src/src/eximstats.src

index 223c7a7b245b306d1204ed484acb6891366974fa..200f9d524a5e189aa793220c558146c22c08f676 100644 (file)
@@ -1,5 +1,5 @@
 #!PERL_COMMAND -w
-# $Cambridge: exim/src/src/eximstats.src,v 1.1 2004/10/07 10:39:01 ph10 Exp $
+# $Cambridge: exim/src/src/eximstats.src,v 1.2 2004/11/24 14:43:57 ph10 Exp $
 
 # Copyright (c) 2001 University of Cambridge.
 # See the file NOTICE for conditions of use and distribution.
 #             Added warnings if required GD::Graph modules are not available or
 #             insufficient -chart* options are specified.
 #
-# 2004-02-20  V1.31 Andrea Balzi
+# 2004-02-20  V1.31 Andrea Balzi 
 #             Only show the Local Sender/Destination links if the tables exist.
 #
+# 2004-07-05  V1.32 Steve Campbell
+#             Fix '-merge -h0' divide by zero error.
+#
+# 2004-07-15  V1.33 Steve Campbell
+#             Documentation update - I've converted the subroutine
+#             documentation from POD to comments.
 
 
 =head1 NAME
@@ -190,6 +196,7 @@ eximstats - generates statistics from Exim mainlog files.
 =head1 SYNOPSIS
 
  eximstats [Options] mainlog1 mainlog2 ... > report.txt
+ eximstats -html [Options] mainlog1 mainlog2 ... > report.html
  eximstats -merge [Options] report.1.txt report.2.txt ... > weekly_report.txt
 
 Options:
@@ -371,11 +378,6 @@ and delivered log lines are in different files, which can happen
 when you have multiple mail servers and a message cannot be
 immeadiately delivered. Fixing this could be tricky...
 
-=head1 SUBROUTINES
-
-The following section will only be of interest to the
-program maintainers:
-
 =cut
 
 use integer;
@@ -411,7 +413,7 @@ use vars qw($COLUMN_WIDTHS);
 
 @days_per_month = (0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334);
 $gig     = 1024 * 1024 * 1024;
-$VERSION = '1.31';
+$VERSION = '1.33';
 
 # How much space do we allow for the Hosts/Domains/Emails/Edomains column headers?
 $COLUMN_WIDTHS = 8;
@@ -465,21 +467,20 @@ use vars qw(%report_totals);
 ##################################################
 
 
-=head2 volume_rounded();
-
- $rounded_volume = volume_rounded($bytes,$gigabytes);
-
-Given a data size in bytes, round it to KB, MB, or GB
-as appropriate.
-
-Eg 12000 => 12KB, 15000000 => 14GB, etc.
-
-Note: I've experimented with Math::BigInt and it results in a 33%
-performance degredation as opposed to storing numbers split into
-bytes and gigabytes.
-
-=cut
-
+#######################################################################
+# volume_rounded();
+#
+# $rounded_volume = volume_rounded($bytes,$gigabytes);
+#
+# Given a data size in bytes, round it to KB, MB, or GB
+# as appropriate.
+#
+# Eg 12000 => 12KB, 15000000 => 14GB, etc.
+#
+# Note: I've experimented with Math::BigInt and it results in a 33%
+# performance degredation as opposed to storing numbers split into
+# bytes and gigabytes.
+#######################################################################
 sub volume_rounded {
   my($x,$g) = @_;
   $x = 0 unless $x;
@@ -522,21 +523,20 @@ sub volume_rounded {
 }
 
 
-=head2 un_round();
-
- un_round($rounded_volume,\$bytes,\$gigabytes);
-
-Given a volume in KB, MB or GB, as generated by volume_rounded(),
-do the reverse transformation and convert it back into Bytes and Gigabytes.
-These are added to the $bytes and $gigabytes parameters.
-
-Given a data size in bytes, round it to KB, MB, or GB
-as appropriate.
-
-EG: 500 => (500,0), 14GB => (0,14), etc.
-
-=cut
-
+#######################################################################
+# un_round();
+# 
+#  un_round($rounded_volume,\$bytes,\$gigabytes);
+# 
+# Given a volume in KB, MB or GB, as generated by volume_rounded(),
+# do the reverse transformation and convert it back into Bytes and Gigabytes.
+# These are added to the $bytes and $gigabytes parameters.
+# 
+# Given a data size in bytes, round it to KB, MB, or GB
+# as appropriate.
+# 
+# EG: 500 => (500,0), 14GB => (0,14), etc.
+#######################################################################
 sub un_round {
   my($rounded,$bytes_sref,$gigabytes_sref) = @_;
 
@@ -561,40 +561,37 @@ sub un_round {
 }
 
 
-=head2 add_volume();
-
-  add_volume(\$bytes,\$gigs,$size);
-
-Add $size to $bytes/$gigs where this is a number split into
-bytes ($bytes) and gigabytes ($gigs). This is significantly
-faster than using Math::BigInt.
-
-=cut
-
+#######################################################################
+# add_volume();
+# 
+#   add_volume(\$bytes,\$gigs,$size);
+# 
+# Add $size to $bytes/$gigs where this is a number split into
+# bytes ($bytes) and gigabytes ($gigs). This is significantly
+# faster than using Math::BigInt.
+#######################################################################
 sub add_volume {
-my($bytes_ref,$gigs_ref,$size) = @_;
-$$bytes_ref = 0 if ! defined $$bytes_ref;
-$$gigs_ref = 0 if ! defined $$gigs_ref;
-$$bytes_ref += $size;
-while ($$bytes_ref > $gig)
-  {
-  $$gigs_ref++;
-  $$bytes_ref -= $gig;
+  my($bytes_ref,$gigs_ref,$size) = @_;
+  $$bytes_ref = 0 if ! defined $$bytes_ref;
+  $$gigs_ref = 0 if ! defined $$gigs_ref;
+  $$bytes_ref += $size;
+  while ($$bytes_ref > $gig) {
+    $$gigs_ref++;
+    $$bytes_ref -= $gig;
   }
 }
 
 
-=head2 format_time();
-
- $formatted_time = format_time($seconds);
-
-Given a time in seconds, break it down into
-weeks, days, hours, minutes, and seconds.
-
-Eg 12005 => 3h20m5s
-
-=cut
-
+#######################################################################
+# format_time();
+# 
+#  $formatted_time = format_time($seconds);
+# 
+# Given a time in seconds, break it down into
+# weeks, days, hours, minutes, and seconds.
+# 
+# Eg 12005 => 3h20m5s
+#######################################################################
 sub format_time {
 my($t) = pop @_;
 my($s) = $t % 60;
@@ -615,16 +612,15 @@ $p;
 }
 
 
-=head2 unformat_time();
-
- $seconds = unformat_time($formatted_time);
-
-Given a time in weeks, days, hours, minutes, or seconds, convert it to seconds.
-
-Eg 3h20m5s => 12005
-
-=cut
-
+#######################################################################
+#  unformat_time();
+# 
+#  $seconds = unformat_time($formatted_time);
+# 
+# Given a time in weeks, days, hours, minutes, or seconds, convert it to seconds.
+# 
+# Eg 3h20m5s => 12005
+#######################################################################
 sub unformat_time {
   my($formated_time) = pop @_;
   my $time = 0;
@@ -640,33 +636,32 @@ sub unformat_time {
 }
 
 
-=head2 seconds();
-
- $time = seconds($timestamp);
-
-Given a time-of-day timestamp, convert it into a time() value using
-POSIX::mktime.  We expect the timestamp to be of the form
-"$year-$mon-$day $hour:$min:$sec", with month going from 1 to 12,
-and the year to be absolute (we do the necessary conversions). The
-timestamp may be followed with an offset from UTC like "+$hh$mm"; if the
-offset is not present, and we have not been told that the log is in UTC
-(with the -utc option), then we adjust the time by the current local
-time offset so that it can be compared with the time recorded in message
-IDs, which is UTC.
-
-To improve performance, we only use mktime on the date ($year-$mon-$day),
-and only calculate it if the date is different to the previous time we
-came here. We then add on seconds for the '$hour:$min:$sec'.
-
-We also store the results of the last conversion done, and only
-recalculate if the date is different.
-
-We used to have the '-cache' flag which would store the results of the
-mktime() call. However, the current way of just using mktime() on the
-date obsoletes this.
-
-=cut
-
+#######################################################################
+# seconds();
+# 
+#  $time = seconds($timestamp);
+# 
+# Given a time-of-day timestamp, convert it into a time() value using
+# POSIX::mktime.  We expect the timestamp to be of the form
+# "$year-$mon-$day $hour:$min:$sec", with month going from 1 to 12,
+# and the year to be absolute (we do the necessary conversions). The
+# timestamp may be followed with an offset from UTC like "+$hh$mm"; if the
+# offset is not present, and we have not been told that the log is in UTC
+# (with the -utc option), then we adjust the time by the current local
+# time offset so that it can be compared with the time recorded in message
+# IDs, which is UTC.
+# 
+# To improve performance, we only use mktime on the date ($year-$mon-$day),
+# and only calculate it if the date is different to the previous time we
+# came here. We then add on seconds for the '$hour:$min:$sec'.
+# 
+# We also store the results of the last conversion done, and only
+# recalculate if the date is different.
+# 
+# We used to have the '-cache' flag which would store the results of the
+# mktime() call. However, the current way of just using mktime() on the
+# date obsoletes this.
+#######################################################################
 sub seconds {
   my($timestamp) = @_;
 
@@ -708,14 +703,13 @@ sub seconds {
 }
 
 
-=head2 id_seconds();
-
- $time = id_seconds($message_id);
-
-Given a message ID, convert it into a time() value.
-
-=cut
-
+#######################################################################
+#  id_seconds();
+# 
+#  $time = id_seconds($message_id);
+# 
+# Given a message ID, convert it into a time() value.
+#######################################################################
 sub id_seconds {
 my($sub_id) = substr((pop @_), 0, 6);
 my($s) = 0;
@@ -726,18 +720,18 @@ $s;
 
 
 
-=head2 calculate_localtime_offset();
-
- $localtime_offset = calculate_localtime_offset();
-
-Calculate the the localtime offset from gmtime in seconds.
-
- $localtime = time() + $localtime_offset.
-
-These are the same semantics as ISO 8601 and RFC 2822 timezone offsets.
-(West is negative, East is positive.)
-
-=cut
+#######################################################################
+#  calculate_localtime_offset();
+# 
+#  $localtime_offset = calculate_localtime_offset();
+# 
+# Calculate the the localtime offset from gmtime in seconds.
+# 
+#  $localtime = time() + $localtime_offset.
+# 
+# These are the same semantics as ISO 8601 and RFC 2822 timezone offsets.
+# (West is negative, East is positive.)
+#######################################################################
 
 # $localtime = gmtime() + $localtime_offset.  OLD COMMENT
 # This subroutine commented out as it's not currently in use.
@@ -762,16 +756,15 @@ sub calculate_localtime_offset {
 }
 
 
-=head2 print_queue_times();
-
- $time = print_queue_times($message_type,\@queue_times,$queue_more_than);
-
-Given the type of messages being output, the array of message queue times,
-and the number of messages which exceeded the queue times, print out
-a table.
-
-=cut
-
+#######################################################################
+# print_queue_times();
+# 
+#  $time = print_queue_times($message_type,\@queue_times,$queue_more_than);
+# 
+# Given the type of messages being output, the array of message queue times,
+# and the number of messages which exceeded the queue times, print out
+# a table.
+#######################################################################
 sub print_queue_times {
 no integer;
 my($string,$array,$queue_more_than) = @_;
@@ -866,15 +859,14 @@ print "\n";
 
 
 
-=head2 print_histogram();
-
- print_histogram('Deliverieds|Messages received',@interval_count);
-
-Print a histogram of the messages delivered/received per time slot
-(hour by default).
-
-=cut
-
+#######################################################################
+# print_histogram();
+# 
+#  print_histogram('Deliverieds|Messages received',@interval_count);
+# 
+# Print a histogram of the messages delivered/received per time slot
+# (hour by default).
+#######################################################################
 sub print_histogram {
 my($text) = shift;
 my(@interval_count) = @_;
@@ -982,16 +974,15 @@ if ($html)
 
 
 
-=head2 print_league_table();
-
- print_league_table($league_table_type,\%message_count,\%message_data,\%message_data_gigs);
-
-Given hashes of message count and message data, which are keyed by
-the table type (eg by the sending host), print a league table
-showing the top $topcount (defaults to 50).
-
-=cut
-
+#######################################################################
+# print_league_table();
+# 
+#  print_league_table($league_table_type,\%message_count,\%message_data,\%message_data_gigs);
+# 
+# Given hashes of message count and message data, which are keyed by
+# the table type (eg by the sending host), print a league table
+# showing the top $topcount (defaults to 50).
+#######################################################################
 sub print_league_table {
 my($text,$m_count,$m_data,$m_data_gigs) = @_;
 my($name) = ($topcount == 1)? "$text" : "$topcount ${text}s";
@@ -1148,27 +1139,26 @@ print "\n";
 }
 
 
-=head2 top_n_sort();
-
-  @sorted_keys = top_n_sort($n,$href1,$href2,$href3);
-
-Given a hash which has numerical values, return the sorted $n keys which
-point to the top values. The second and third hashes are used as
-tiebreakers. They all must have the same keys.
-
-The idea behind this routine is that when you only want to see the
-top n members of a set, rather than sorting the entire set and then
-plucking off the top n, sort through the stack as you go, discarding
-any member which is lower than your current n'th highest member.
-
-This proves to be an order of magnitude faster for large hashes.
-On 200,000 lines of mainlog it benchmarked 9 times faster.
-On 700,000 lines of mainlog it benchmarked 13.8 times faster.
-
-We assume the values are > 0.
-
-=cut
-
+#######################################################################
+# top_n_sort();
+# 
+#   @sorted_keys = top_n_sort($n,$href1,$href2,$href3);
+# 
+# Given a hash which has numerical values, return the sorted $n keys which
+# point to the top values. The second and third hashes are used as
+# tiebreakers. They all must have the same keys.
+# 
+# The idea behind this routine is that when you only want to see the
+# top n members of a set, rather than sorting the entire set and then
+# plucking off the top n, sort through the stack as you go, discarding
+# any member which is lower than your current n'th highest member.
+# 
+# This proves to be an order of magnitude faster for large hashes.
+# On 200,000 lines of mainlog it benchmarked 9 times faster.
+# On 700,000 lines of mainlog it benchmarked 13.8 times faster.
+# 
+# We assume the values are > 0.
+#######################################################################
 sub top_n_sort {
   my($n,$href1,$href2,$href3) = @_;
 
@@ -1192,15 +1182,15 @@ sub top_n_sort {
   my $n_minus_1 = $n - 1;
   my $n_minus_2 = $n - 2;
 
-  # Pick out the top $n keys.
+  # Pick out the top $n keys. 
   my($key,$value1,$value2,$value3,$i,$comparison,$insert_position);
   while (($key,$value1) = each %$href1) {
 
     #print STDERR "key $key ($value1,",$href2->{$key},",",$href3->{$key},") <=> ($minimum_value1,$minimum_value2,$minimum_value3)\n";
-
+    
     # Check to see that the new value is bigger than the lowest of the
     # top n keys that we're keeping.
-    $comparison = $value1        <=> $minimum_value1 ||
+    $comparison = $value1        <=> $minimum_value1 || 
                  $href2->{$key} <=> $minimum_value2 ||
                  $href3->{$key} <=> $minimum_value3 ||
                  $top_n_key cmp $key;
@@ -1227,7 +1217,7 @@ sub top_n_sort {
     for ($i = 0; $i < $n_minus_1; $i++) {
       $top_n_key = $top_n_keys[$i];
       if ( ($top_n_key eq '_') ||
-          ( ($value1 <=> $href1->{$top_n_key} ||
+          ( ($value1 <=> $href1->{$top_n_key} || 
               $value2 <=> $href2->{$top_n_key} ||
              $value3 <=> $href3->{$top_n_key} ||
              $top_n_key cmp $key) == 1
@@ -1257,14 +1247,13 @@ sub top_n_sort {
 }
 
 
-=head2 html_header();
-
- $header = html_header($title);
-
-Print our HTML header and start the <body> block.
-
-=cut
-
+#######################################################################
+# html_header();
+# 
+#  $header = html_header($title);
+# 
+# Print our HTML header and start the <body> block.
+#######################################################################
 sub html_header {
   my($title) = @_;
   my $text = << "EoText";
@@ -1282,14 +1271,13 @@ EoText
 
 
 
-=head2 help();
-
- help();
-
-Display usage instructions and exit.
-
-=cut
-
+#######################################################################
+# help();
+# 
+#  help();
+# 
+# Display usage instructions and exit.
+#######################################################################
 sub help {
   print << "EoText";
 
@@ -1348,22 +1336,21 @@ EoText
 
 
 
-=head2 generate_parser();
-
- $parser = generate_parser();
-
-This subroutine generates the parsing routine which will be
-used to parse the mainlog. We take the base operation, and remove bits not in use.
-This improves performance depending on what bits you take out or add.
-
-I've tested using study(), but this does not improve performance.
-
-We store our parsing routing in a variable, and process it looking for #IFDEF (Expression)
-or #IFNDEF (Expression) statements and corresponding #ENDIF (Expression) statements. If
-the expression evaluates to true, then it is included/excluded accordingly.
-
-=cut
-
+#######################################################################
+# generate_parser();
+# 
+#  $parser = generate_parser();
+# 
+# This subroutine generates the parsing routine which will be
+# used to parse the mainlog. We take the base operation, and remove bits not in use.
+# This improves performance depending on what bits you take out or add.
+# 
+# I've tested using study(), but this does not improve performance.
+# 
+# We store our parsing routing in a variable, and process it looking for #IFDEF (Expression)
+# or #IFNDEF (Expression) statements and corresponding #ENDIF (Expression) statements. If
+# the expression evaluates to true, then it is included/excluded accordingly.
+#######################################################################
 sub generate_parser {
   my $parser = '
   my($ip,$host,$email,$edomain,$domain,$thissize,$size,$old,$new);
@@ -1693,15 +1680,14 @@ sub generate_parser {
 
 
 
-=head2 parse();
-
- parse($parser,\*FILEHANDLE);
-
-This subroutine accepts a parser and a filehandle from main and parses each
-line. We store the results into global variables.
-
-=cut
-
+#######################################################################
+# parse();
+# 
+#  parse($parser,\*FILEHANDLE);
+# 
+# This subroutine accepts a parser and a filehandle from main and parses each
+# line. We store the results into global variables.
+#######################################################################
 sub parse {
   my($parser,$fh) = @_;
 
@@ -1717,14 +1703,13 @@ sub parse {
 
 
 
-=head2 print_header();
-
- print_header();
-
-Print our headers and contents.
-
-=cut
-
+#######################################################################
+# print_header();
+# 
+#  print_header();
+# 
+# Print our headers and contents.
+#######################################################################
 sub print_header {
 
   my $title = "Exim statistics from $begin to $end";
@@ -1774,14 +1759,13 @@ sub print_header {
 }
 
 
-=head2 print_grandtotals();
-
- print_grandtotals();
-
-Print the grand totals.
-
-=cut
-
+#######################################################################
+# print_grandtotals();
+# 
+#  print_grandtotals();
+# 
+# Print the grand totals.
+#######################################################################
 sub print_grandtotals {
 
   # Get the sender by headings and results. This is complicated as we can have
@@ -1862,14 +1846,13 @@ EoText
 }
 
 
-=head2 print_user_patterns()
-
- print_user_patterns();
-
-Print the counts of user specified patterns.
-
-=cut
-
+#######################################################################
+# print_user_patterns()
+# 
+#  print_user_patterns();
+# 
+# Print the counts of user specified patterns.
+#######################################################################
 sub print_user_patterns {
   my($format1);
 
@@ -1911,14 +1894,13 @@ sub print_user_patterns {
 }
 
 
-=head2 print_transport();
-
- print_transport();
-
-Print totals by transport.
-
-=cut
-
+#######################################################################
+# print_transport();
+# 
+#  print_transport();
+# 
+# Print totals by transport.
+#######################################################################
 sub print_transport {
   my($format1);
   my(@chartdatanames);
@@ -2017,14 +1999,13 @@ sub print_transport {
 
 
 
-=head2 print_relay();
-
- print_relay();
-
-Print our totals by relay.
-
-=cut
-
+#######################################################################
+# print_relay();
+# 
+#  print_relay();
+# 
+# Print our totals by relay.
+#######################################################################
 sub print_relay {
   my $temp = "Relayed messages";
   print "<hr><a name=\"$temp\"></a><h2>$temp</h2>\n" if $html;
@@ -2064,15 +2045,14 @@ sub print_relay {
 
 
 
-=head2 print_errors();
-
- print_errors();
-
-Print our errors. In HTML, we display them as a list rather than a table -
-Netscape doesn't like large tables!
-
-=cut
-
+#######################################################################
+# print_errors();
+# 
+#  print_errors();
+# 
+# Print our errors. In HTML, we display them as a list rather than a table -
+# Netscape doesn't like large tables!
+#######################################################################
 sub print_errors {
   my $total_errors = 0;
 
@@ -2095,7 +2075,7 @@ sub print_errors {
       $text =~ s/\s\s+/ /g;    #Convert multiple spaces to a single space.
       $total_errors += $errors_count{$key};
       if ($html) {
-
+        
         #Translate HTML tag characters. Sergey Sholokh.
         $text =~ s/\</\&lt\;/g;
         $text =~ s/\>/\&gt\;/g;
@@ -2123,42 +2103,41 @@ sub print_errors {
 }
 
 
-=head2 parse_old_eximstat_reports();
-
- parse_old_eximstat_reports($fh);
-
-Parse old eximstat output so we can merge daily stats to weekly stats and weekly to monthly etc.
-
-To test that the merging still works after changes, do something like the following.
-All the diffs should produce no output.
-
- options='-bydomain -byemail -byhost -byedomain'
- options="$options -pattern 'Completed Messages' /Completed/"
- options="$options -pattern 'Received Messages' /<=/"
-
- ./eximstats $options mainlog > mainlog.txt
- ./eximstats $options -merge mainlog.txt > mainlog.2.txt
- diff mainlog.txt mainlog.2.txt
-
- ./eximstats $options -html mainlog > mainlog.html
- ./eximstats $options -merge -html mainlog.txt  > mainlog.2.html
- diff mainlog.html mainlog.2.html
-
- ./eximstats $options -merge mainlog.html > mainlog.3.txt
- diff mainlog.txt mainlog.3.txt
-
- ./eximstats $options -merge -html mainlog.html > mainlog.3.html
- diff mainlog.html mainlog.3.html
-
- ./eximstats $options -nvr   mainlog > mainlog.nvr.txt
- ./eximstats $options -merge mainlog.nvr.txt > mainlog.4.txt
- diff mainlog.txt mainlog.4.txt
-
- # double_mainlog.txt should have twice the values that mainlog.txt has.
- ./eximstats $options mainlog mainlog > double_mainlog.txt
-
-=cut
-
+#######################################################################
+# parse_old_eximstat_reports();
+# 
+#  parse_old_eximstat_reports($fh);
+# 
+# Parse old eximstat output so we can merge daily stats to weekly stats and weekly to monthly etc.
+# 
+# To test that the merging still works after changes, do something like the following.
+# All the diffs should produce no output.
+# 
+#  options='-bydomain -byemail -byhost -byedomain'
+#  options="$options -pattern 'Completed Messages' /Completed/"
+#  options="$options -pattern 'Received Messages' /<=/"
+# 
+#  ./eximstats $options mainlog > mainlog.txt
+#  ./eximstats $options -merge mainlog.txt > mainlog.2.txt
+#  diff mainlog.txt mainlog.2.txt
+# 
+#  ./eximstats $options -html mainlog > mainlog.html
+#  ./eximstats $options -merge -html mainlog.txt  > mainlog.2.html
+#  diff mainlog.html mainlog.2.html
+# 
+#  ./eximstats $options -merge mainlog.html > mainlog.3.txt
+#  diff mainlog.txt mainlog.3.txt
+# 
+#  ./eximstats $options -merge -html mainlog.html > mainlog.3.html
+#  diff mainlog.html mainlog.3.html
+# 
+#  ./eximstats $options -nvr   mainlog > mainlog.nvr.txt
+#  ./eximstats $options -merge mainlog.nvr.txt > mainlog.4.txt
+#  diff mainlog.txt mainlog.4.txt
+# 
+#  # double_mainlog.txt should have twice the values that mainlog.txt has.
+#  ./eximstats $options mainlog mainlog > double_mainlog.txt
+#######################################################################
 sub parse_old_eximstat_reports {
   my($fh) = @_;
 
@@ -2245,10 +2224,10 @@ sub parse_old_eximstat_reports {
        next unless $reached_table;
        print STDERR "Parsing $_" if $debug;
        if (/^(\d+):(\d+)\s+(\d+)/) {           #hh:mm start time format ?
-         $$interval_aref[($1*60 + $2)/$hist_interval] += $3;
+         $$interval_aref[($1*60 + $2)/$hist_interval] += $3 if $hist_opt;
        }
        elsif (/^(\d+)-(\d+)\s+(\d+)/) {        #hh-hh start-end time format ?
-         $$interval_aref[($1*60)/$hist_interval] += $3;
+         $$interval_aref[($1*60)/$hist_interval] += $3 if $hist_opt;
        }
        else {                                  #Finished the table ?
          last;
@@ -2483,15 +2462,14 @@ sub parse_old_eximstat_reports {
 
 
 
-=head2 update_relayed();
-
- update_relayed($count,$sender,$recipient);
-
-Adds an entry into the %relayed hash. Currently only used when
-merging reports.
-
-=cut
-
+#######################################################################
+# update_relayed();
+# 
+#  update_relayed($count,$sender,$recipient);
+# 
+# Adds an entry into the %relayed hash. Currently only used when
+# merging reports.
+#######################################################################
 sub update_relayed {
   my($count,$sender,$recipient) = @_;
 
@@ -2509,18 +2487,17 @@ sub update_relayed {
 }
 
 
-=head2 add_to_totals();
-
- add_to_totals(\%totals,\@keys,$values);
-
-Given a line of space seperated values, add them into the provided hash using @keys
-as the hash keys.
-
-If the value contains a '%', then the value is set rather than added. Otherwise, we
-convert the value to bytes and gigs. The gigs get added to I<Key>-gigs.
-
-=cut
-
+#######################################################################
+# add_to_totals();
+# 
+#  add_to_totals(\%totals,\@keys,$values);
+# 
+# Given a line of space seperated values, add them into the provided hash using @keys
+# as the hash keys.
+# 
+# If the value contains a '%', then the value is set rather than added. Otherwise, we
+# convert the value to bytes and gigs. The gigs get added to I<Key>-gigs.
+#######################################################################
 sub add_to_totals {
   my($totals_href,$keys_aref,$values) = @_;
   my(@values) = split(/\s+/,$values);
@@ -2540,16 +2517,15 @@ sub add_to_totals {
   }
 }
 
-=head2 get_report_total();
-
- $total = get_report_total(\%hash,$key);
-
-If %hash contains values split into Units and Gigs, we calculate and return
-
-  $hash{$key} + 1024*1024*1024 * $hash{"${key}-gigs"}
-
-=cut
-
+#######################################################################
+# get_report_total();
+# 
+#  $total = get_report_total(\%hash,$key);
+# 
+# If %hash contains values split into Units and Gigs, we calculate and return
+# 
+#   $hash{$key} + 1024*1024*1024 * $hash{"${key}-gigs"}
+#######################################################################
 sub get_report_total {
   no integer;
   my($hash_ref,$key) = @_;
@@ -2559,15 +2535,14 @@ sub get_report_total {
   return $$hash_ref{$key} || 0;
 }
 
-=head2 html2txt();
-
- $text_line = html2txt($html_line);
-
-Convert a line from html to text. Currently we just convert HTML tags to spaces
-and convert &gt;, &lt;, and &nbsp; tags back.
-
-=cut
-
+#######################################################################
+# html2txt();
+# 
+#  $text_line = html2txt($html_line);
+# 
+# Convert a line from html to text. Currently we just convert HTML tags to spaces
+# and convert &gt;, &lt;, and &nbsp; tags back.
+#######################################################################
 sub html2txt {
   ($_) = @_;
 
@@ -2583,24 +2558,23 @@ sub html2txt {
   return($_);
 }
 
-=head2 get_next_arg();
-
- $arg = get_next_arg();
-
-Because eximstats arguments are often passed as variables,
-we can't rely on shell parsing to deal with quotes. This
-subroutine returns $ARGV[1] and does a shift. If $ARGV[1]
-starts with a quote (' or "), and doesn't end in one, then
-we append the next argument to it and shift again. We repeat
-until we've got all of the argument.
-
-This isn't perfect as all white space gets reduced to one space,
-but it's as good as we can get! If it's esential that spacing
-be preserved precisely, then you get that by not using shell
-variables.
-
-=cut
-
+#######################################################################
+# get_next_arg();
+# 
+#  $arg = get_next_arg();
+# 
+# Because eximstats arguments are often passed as variables,
+# we can't rely on shell parsing to deal with quotes. This
+# subroutine returns $ARGV[1] and does a shift. If $ARGV[1]
+# starts with a quote (' or "), and doesn't end in one, then
+# we append the next argument to it and shift again. We repeat
+# until we've got all of the argument.
+# 
+# This isn't perfect as all white space gets reduced to one space,
+# but it's as good as we can get! If it's esential that spacing
+# be preserved precisely, then you get that by not using shell
+# variables.
+#######################################################################
 sub get_next_arg {
   my $arg = '';
   my $matched_pattern = 0;