#!/usr/bin/perl -w

use strict;

my @inputdata;
my $started = 0;
while (<>)
	{
	chomp;
	last if $started and /^---End table---$/;
	push @inputdata, $_ if $started;
	$started = 1 if /^---Start table---$/;
	}

die "It would seem no input was found\n" unless @inputdata;

# 0 is ignored
# 1 is assigned by strxfrm to end of pass
# 2 is space or tabelator -- end of word in pass 0 and 1
# 255 (or max in pass) is a compound char notificator

my @tables = ( [], [], [], [] );
my %compound = ( );
my @maxval = ( 3, 3, 3, 3 );
my @value = ( 3, 3, 3, 3 );

my $line;
for $line (@inputdata)
	{
	my $only3 = 0;
	$value[1] = $value[2] = 3;
	if ($line =~ s/^\s+//)
		{
		$value[3]++;
		$only3 = 1;
		}
	while ($line ne '')
		{
		for (0 .. 3)
			{ $maxval[$_] = $value[$_] if $maxval[$_] < $value[$_]; }
		if ($line =~ s/^\s+//)
			{ $value[1]++ unless $only3; $value[2] = 3; next; }
		my $firstord;
		if ($line =~ s/^<([cC]h|CH)>//)
			{
			$firstord = ord $1;
			}
		else
			{
			$firstord = ord $line;
			$line = substr $line, 1;
			
			}
		
		for (0 .. 3)
			{
			if ($only3 and $_ < 3)
				{ $tables[$_][$firstord] = 0; }
			else
				{ $tables[$_][$firstord] = $value[$_]; }
			}	

		$value[2]++ unless $only3;
		$value[3]++ if $only3;
		}
	$value[0]++ unless $only3;
	}

my $pass;
for $pass (0 .. 3)
	{
	$maxval[$pass]++;
	for (0 .. 255)
		{ $tables[$pass][$_] = 0 unless defined $tables[$pass][$_]; }
	print map { sprintf "%c => %d\t", ( $_ < 32 ? ord('.') : $_ ),
				$tables[$pass][$_] } (0 .. 255);
	print "\nMax val: $maxval[$pass]\n";
	}
__END__

my $pass;
for $pass (0 .. 3)
	{
	$tables[$pass][ord ' '] = 2;
	$tables[$pass][ord "\t"] = 2;
	my $min = 3;
	if ($pass == 3)	{ $min = 4; }
	my $i = 3;


	my $line;
	for $line (@inputdata)
		{
		my $line = $line;
		my $nearlynull = 0;
		$nearlynull = 1 if $line =~ s/^\s+//;
		next if $nearlynull and $pass != 3;
		my @items;
		if ($pass == 0)
			{
			$line =~ s/\s+//g;
			@items = ( $line );
			}
		elsif ($pass == 1)
			{
			$i = $min;
			@items = split /\s+/, $line;
			}
		else
			{
			@items = grep { defined $_ and not /^\s*$/ }
				$line =~ /(<(?:[cC]h|CH)>|[\000-\377])/go;	
			}
		
		for (@items)
			{
			while ($_ ne '')
				{
				if (s/^<([cC]h|CH)>//)
					{
					my $string = $+;
					$compound{$string}[$pass] = $i;
					$string =~ /^[\000-\377]/o;
					my $ch = $&;
					$compound{$ch}[$pass] =
						$tables[$pass][ord $ch];
					}
				else
					{
					s/^[\000-\377]//o;
					my $ch = $&;
					$tables[$pass][ord $ch] = $i;
					}
				}
			$i++;	
			}
		}
	$maxval[$pass] = $i;
	
	my $tag;
	for $tag (keys %compound)
		{
		if (defined $compound{$tag}[$pass])
			{
			$tag =~ /^[\000-\377]/o;
			$tables[$pass][ord $&] = $tag;
			}
		}
	my $ord;
	if ($pass == 3)
		{
		for $ord (0 .. 31)
			{
			$tables[$pass][$ord] = $i
					unless defined $tables[$pass][$ord];
			$tables[$pass][$ord + 128] = $i
				unless defined $tables[$pass][$ord + 128];
			$i++;
			}
		for $ord (0 .. 255)
			{
			$tables[$pass][$ord] = $i++
					unless defined $tables[$pass][$ord];
			}
		}
	else
		{
		for $ord (0 .. 255)
			{ $tables[$pass][$ord] = 0
					unless defined $tables[$pass][$ord]; }
		}
	}

my $type = "uchar";
print "#define uchar unsigned char\n";
print "$type * CZ_SORT_TABLE[] = {\n";

for $pass (0 .. 3)
	{
	print qq!\t"!;
	my $ord;
	for $ord (0 .. 255)
		{
		printf "\\%03o", $tables[$pass][$ord];
		}
	print qq!",\n!;
	}

print "};\n";

my $comp;
for $comp (keys %compound)
	{
	print "$type CZ_SORT_VALUE_$comp\[\] = {\n";
	for $pass (0 .. 3)
		{
		printf "\t($type)'\\%03o',", $compound{$comp}[$pass];
		}
	print "\n\t};\n";
	}

