#!/usr/bin/perl -w
#
# $Id: barchart.pl,v 1.2 2000/01/28 16:07:37 kjc Exp $
#
# usage: barchart.pl < tcpdstat_output
#	barchart.pl reads the output of tcpdstat from stdin, and then,
#	create a png bartchart.
#	the name of the output png file is "<id>.png", <id> is extracted
#	from the "Id:" field of the input file.
#	input file format:
#		Id: <id>
#		[<level>] name (<dontcare>)  (<percent>)
#

$outfile = "date.png";
$infile = "fly.temp";

$scale=3;

$xoff = 8;
$yoff = 6;
$hight = 8;

$xmax = (100 + $xoff*2) * $scale;
$ymax = (($yoff + $hight) * 3 + $hight) * $scale;

# char size: 
#    tiny(5x8) small(6x12) medium(7x13,bold), large(8x16), giant(9x15,bold)
$chartype = "small";
$charhight = 12;
$charwidth = 6;

# color
$r = 80;
$g = 140;
$b = 255;

$toolpath = ".";
if ($0 =~ /(.*)\/.*/) {
    $toolpath = $1;
}

$flyprog = "$toolpath/../bin/fly";

sub validcolor ($) {
    my $val = shift;

    if ($val < 0) {
	$val = 0;
    }
    if ($val > 255) {
	$val = 255;
    }
    return $val;
}

sub drawbox ($$$$$$$$$) {
    my ($x1, $y1, $x2, $y2, $name, $val, $r, $g, $b) = @_;
    my ($sx1, $sx2, $sy1, $sy2, $cx, $cy, $r0, $g0, $b0, $strval);
      
    $sx1 = $x1 + 6;
    $sx2 = $x2 + 6;
    $sy1 = $y1 - 4;
    $sy2 = $y2 - 4;

    $r0 = validcolor($r);
    $g0 = validcolor($g);
    $b0 = validcolor($b);
    print FLY "frect $x1,$y1,$x2,$y2,$r0,$g0,$b0\n";
    print FLY "rect $x1,$y1,$x2,$y2,0,0,0\n";

    $r0 = validcolor($r - 30);
    $g0 = validcolor($g - 30);
    $b0 = validcolor($b - 30);
    print FLY "fpoly $r0,$g0,$b0,$x1,$y1,$sx1,$sy1,$sx2,$sy1,$x2,$y1\n";
    print FLY "poly 0,0,0,$x1,$y1,$sx1,$sy1,$sx2,$sy1,$x2,$y1\n";

    $r0 = validcolor($r - 60);
    $g0 = validcolor($g - 60);
    $b0 = validcolor($b - 60);
    print FLY "fpoly $r0,$g0,$b0,$x2,$y1,$sx2,$sy1,$sx2,$sy2,$x2,$y2\n";
    print FLY "poly 0,0,0,$x2,$y1,$sx2,$sy1,$sx2,$sy2,$x2,$y2\n";

    $cx = ($x1 + $x2) / 2 - length($name) * $charwidth / 2;
    if ($cx < $x1) {
	$cx = $x1;
    }
    $cy = ($y1 + $y2) / 2 - $charhight;
    print FLY "string 0,0,0,$cx,$cy,$chartype,$name\n";

    if ($val > 0) {
	$strval = sprintf("%d%%", $val + 0.5);
	$cx = ($x1 + $x2) / 2 - length($strval) * $charwidth / 2;
	if ($cx < $x1) {
	    $cx = $x1;
	}
	$cy = ($y1 + $y2) / 2;
	print FLY "string 0,0,0,$cx,$cy,$chartype,$strval\n";
    }
}

while (<>) {
    # find Id
    if (/^Id:\s*(\w+)/) {
	$outfile = $1 . ".png";
	last;
    }
}

unless ($_) { die "Can't find Id info!\n"; }

open(FLY,"> $infile");
print FLY "new\n";
print FLY "size $xmax,$ymax\n";
print FLY "fill 1,1,255,255,255\n";

$cur_level = 0;
$x1 = $xoff * $scale;
$x2 = $x1 + 100 * $scale;
$y1 = 0 - $hight * $scale;
$y2 = $y1 + $hight * $scale;

while (<>) {
    # find "[$level]  $name  (xxx)   ($val)"
    if (/^\[(\d+)\]\s+(\w+).*\(.*\).*\(\s*(\d+\.\d+)%\)/) {
	$level = $1;
	$name = $2;
	$val = $3;

	# don't draw level 0
	next if ($level == 0);
	# skip entries less than 5%
	next if ($val < 4.5);
	# XXX: ignore entries named "other" or "frag".
	#      this should be done by preprocessing.
	next if ($name eq "other");
	next if ($name eq "frag");

	if ($level == $cur_level) {
	    # draw a box on the right side
	    $x1 = $x2;
	    $x2 = $x1 + $val * $scale;
	    $r += 20; $g += 20; $b += 20;

	    drawbox($x1, $y1, $x2, $y2, $name, $val, $r, $g, $b);
	}
	elsif ($level > $cur_level) {
	    # go down and draw a box
	    push @stack, $x1;
	    push @stack, $x2;

	    $x2 = $x1 + $val * $scale;
	    $y1 = $y2 + $yoff * $scale;
	    $y2 = $y1 + $hight * $scale;

	    drawbox($x1, $y1, $x2, $y2, $name, $val, $r, $g, $b);
	}
	else {
	    # draw an "other" box and restore $x1, $x2
	    while ($level < $cur_level) {
		$x1 = $x2;
		$x2 = pop @stack;

		drawbox($x1, $y1, $x2, $y2, "", -1, 200, 200, 200);
	      
		$x1 = pop @stack;
		$y1 = $y1 - ($hight + $yoff) * $scale;
		$y2 = $y1 + $hight * $scale;
		$cur_level--;
	    }

	    $x1 = $x2;
	    $x2 = $x1 + $val * $scale;
	    $r += 20; $g += 20; $b += 20;

	    drawbox($x1, $y1, $x2, $y2, $name, $val, $r, $g, $b);
	}

	$cur_level = $level;
    }
}

# draw "other" boxes
while (0 < $cur_level) {
    $x1 = $x2;
    $x2 = pop @stack;

    drawbox($x1, $y1, $x2, $y2, "", -1, 200, 200, 200);
	      
    $x1 = pop @stack;
    $y1 = $y1 - ($hight + $yoff) * $scale;
    $y2 = $y1 + $hight * $scale;
    $cur_level--;
}

close(FLY);

open(FOO,"$flyprog -q -i $infile -o $outfile |");
while( <FOO> ) {print;}
close(FOO);

unlink($infile);
exit 0;


syntax highlighted by Code2HTML, v. 0.9.1