#!/usr/bin/perl -w
# $Id: calculate_table.in 1.4 Sun, 23 May 1999 17:26:04 +0200 hlovdal $
use strict;

local ($main::CYLINDERS, $main::HEADS, $main::SECTORS_PR_TRACK);
local $main::DISKNAME;
local @main::table;
use vars qw($CYLINDERS $HEADS $SECTORS_PR_TRACK $DISKNAME @table);

sub usage {
	print "usage: $0 table_file\n";
	exit 1;
}

usage() unless ($#ARGV == 0);
usage() unless -r $ARGV[0];
do $ARGV[0];

###############################################################################

my $extpar_abs_start_sect = 0;
my $RSS_save = 0;
# RSS = relative start sect, NOS = number of sectors

my @pointer_entry;
my $parno = 0;

print_header();
print "\tPartition table at Master Boot Record (CHS=0/0/1) offset 0x1BE\n";
print_top();
for ($parno=0; $parno<4; $parno++) {
	my @entry = @{$table[$parno]};
	if ($entry[1] eq 'unused') {
		print_empty_entry($entry[0]);
		next;
	}
	my ($RSS, $NOS) = compute_rss_nos(0, @entry);
	print_entry(0, @entry, $RSS, $NOS);
	if ($entry[2] eq '0x05') {
		@pointer_entry = mkpointer(@entry);
		if ($entry[4] == 0) {
			$RSS_save = 0
		} else {
			$RSS_save = $RSS;
		}
	}
}
print_bottom();

$extpar_abs_start_sect = $RSS_save;
my $max_parno = $#table;
$max_parno-- if (${$table[$max_parno]}[0] eq 'end');

for (; $parno <= $max_parno; $parno++) {
	my @entry = @{$table[$parno]};
	last if ($entry[0] eq 'end');	# backwards compability
	my ($RSS, $NOS) = compute_rss_nos(1, @entry);
	print "\tDrive table at sector CHS=$pointer_entry[3]/0/1 offset 0x1BE\n";
	print_top();
	print_entry(1, @entry, $RSS, $NOS);
	if ($parno == $max_parno) {
		print_empty_entry('    ');
	} else {
		@pointer_entry = mkpointer( @{$table[$parno+1]} );
		my ($rss, $nos) = compute_rss_nos(0, @pointer_entry);
		print_entry(0, @pointer_entry, $rss, $nos);
	}
	print_empty_entry('    ');
	print_empty_entry('    ');
	print_bottom();
}


###############################################################################

sub mkpointer {
	my @entry = @_;
	$entry[0] = '    ';
	$entry[1] = '0x00';
	$entry[2] = '0x05';
	return @entry;
}

sub compute_rss_nos {
	my $is_logical	= shift;
	my $name	= shift;
	my $bootable	= shift;
	my $system	= shift;
	my $start_cyl	= shift;
	my $end_cyl	= shift;
	my ($start_head, $RSS, $NOS);
	if ($start_cyl == 0 or $is_logical) {
		$start_head = 1
	} else {
		$start_head = 0;
	}
	$NOS = ((($end_cyl+1 - $start_cyl) * $HEADS) - $start_head) * $SECTORS_PR_TRACK;
	if ($is_logical) {
		$RSS = ($start_cyl - $pointer_entry[3]) * $HEADS * $SECTORS_PR_TRACK;	# this should usually evaluate to zero
		$RSS += $SECTORS_PR_TRACK;
	} else {
		$RSS = ($start_cyl*$HEADS + $start_head) * $SECTORS_PR_TRACK;
		$RSS -= $extpar_abs_start_sect;
	}
	return ($RSS, $NOS);
}

sub print_empty_entry {
	my $name = shift;
	printf "| %5s  |     0  |   0     0   0 |    0 |   0     0   0 |        0 |        0 |\n", $name;
}

sub print_entry {
	my $is_logical	= shift;
	my $name	= shift;
	my $bootable	= shift;
	my $system	= shift;
	my $start_cyl	= shift;
	my $end_cyl	= shift;
	my $RSS		= shift;
	my $NOS		= shift;
	my $start_head;
	if ($start_cyl == 0 or $is_logical) {
		$start_head = 1
	} else {
		$start_head = 0;
	}
	$start_cyl = 1023 if $start_cyl > 1023;
	$end_cyl   = 1023 if $end_cyl   > 1023;
	printf "| %5s  |  $bootable  |   %d %5s   1 | $system | %3d %5s %3d | %8d | %8d |\n", $name, $start_head, $start_cyl, $HEADS-1, $end_cyl, $SECTORS_PR_TRACK, $RSS, $NOS;
}


sub print_top {
	print <<EOF
+--------+--------+---------------+------+---------------+----------+----------+
| parti- |        |     Start     |      |      End      | Relative |Number of |
| tion   |bootable|Head Cyl Sector|System|Head Cyl Sector|Start Sect| Sectors  |
+--------+--------+---------------+------+---------------+----------+----------+
EOF
	;
}

sub print_bottom {
	print <<EOF
+--------+--------+---------------+------+---------------+----------+----------+

EOF
	;
}

sub centerprint {
	my $msg = shift;
	my $len1 = 78 - length($msg);
	my $len2 = int($len1/2);
	$len1 -= $len2;
	print "#", " " x $len2, $msg, " " x $len1, "#\n";
}

sub print_header {
	print "\n", "#" x 80, "\n#", " " x 78, "#\n";
	centerprint("Partition table printout for $DISKNAME (CHS=$CYLINDERS/$HEADS/$SECTORS_PR_TRACK)");
	centerprint("calculated by $0 version 1.1.3");
	print "#", " " x 78, "#\n", "#" x 80, "\n\n";
}

