#!/usr/bin/perl
#  makeumap.in version 1.5
#  yudit package - Unicode Editor for the X Window System (and Linux) 
#
#  Author: gsinai@iname.com (Gaspar Sinai)
#  GNU Copyright (C) 1997,1998,1999  Gaspar Sinai
# 
#  yudit version 1.5  Copyright(C) 30 November, 1999, Tokyo Japan  Gaspar Sinai
#  yudit version 1.4  Copyright(C) 25 November, 1999, Tokyo Japan  Gaspar Sinai
#  yudit version 1.3  Copyright(C)  5 April,    1999, Tokyo Japan  Gaspar Sinai
#  yudit version 1.2  Copyright(C) 10 December, 1998, Tokyo Japan  Gaspar Sinai
#  yudit version 1.1  Copyright(C) 23 August,   1998, Tokyo Japan  Gaspar Sinai
#  yudit version 1.0  Copyright(C) 17 May,      1998, Tokyo Japan  Gaspar Sinai
#  yudit version 0.99 Copyright(C)  4 April,    1998, Tokyo Japan  Gaspar Sinai
#  yudit version 0.97 Copyright(C)  4 February, 1998, Tokyo Japan  Gaspar Sinai
#  yudit version 0.95 Copyright(C) 10 January,  1998, Tokyo Japan  Gaspar Sinai
#  yudit version 0.94 Copyright(C) 17 December, 1997, Tokyo Japan  Gaspar Sinai
#  yudit version 0.9 Copyright (C)  8 December, 1997, Tokyo Japan  Gaspar Sinai
#  yutex version 0.8 Copyright (C)  5 November, 1997, Tokyo Japan  Gaspar Sinai
#
#  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 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 General Public License for more details.
#
#  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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
#---
#!/usr/local/bin/perl
# createMap.pl
# Gaspar Sinai <gsinai@gol.com>
# this one should create a map between unicode and the current decoding.
# The map may start and end early - late.

$shiftNum = 0;

$column=0;
$unicodeColumn=-1;
$binaryMap = 0;

while (1)
{
	if ($#ARGV >= 0 && $ARGV[0] eq "-high")
	{
		$shiftNum = 1;
		shift;
	}
	elsif ($#ARGV >= 0 && $ARGV[0] eq "-low")
	{
		$shiftNum = -1;
		shift;
	}
	elsif ($#ARGV >= 0 && $ARGV[0] eq "-b")
	{
		$binaryMap = 1;
		shift;
	}
	elsif ($#ARGV > 0 && $ARGV[0] eq "-n")
	{
		$column = $ARGV[1];
		shift; shift;
	}
	elsif ($#ARGV > 0 && $ARGV[0] eq "-u")
	{
		$unicodeColumn=$ARGV[1];
		shift; shift;
	}
	else
	{
		last;
	}
}

#
# We can specify the column number for the local code
# The unicode will always be the last column.
#
if ($#ARGV != 1)
{
	print STDERR  "usage: $0 [-b] [-high|-low] [-n native#] [-u unicode#] file-name map-name\n";
	print STDERR  "       native# is the column of the native code. (0)\n";
	print STDERR  "       unicode#  is the column of the unicode code. (last row)\n";
	exit (1);
}

$inputFile=$ARGV[0];
if ($binaryMap==1)
{
	$outputFile=$ARGV[1] . "." . "bumap";
}
else
{
	$outputFile=$ARGV[1] . "." . "umap";
}
$alias=$ARGV[1];

die "error: can not open $inputFile" unless (open (IN, "< $inputFile"));
die "error: can not open $outputFile" unless (open (OUT, "> $outputFile"));

$localMinL = 2**8-1;
$localMaxL = 0;
$localMinR = 2**8-1;
$localMaxR = 0;

$uniMinL = 2**8-1;
$uniMaxL = 0;
$uniMinR = 2**8-1;
$uniMaxR = 0;

%hexMap = 
(
	"0",0, "1",1,  "2",2, "3",3, "4",4, "5",5, "6",6, "7",7, "8",8, "9",9,
	"a",10, "b", 11, "c",12, "d",13, "e",14, "f",15, 
	"A",10, "B", 11, "C",12, "D",13, "E",14, "F",15, 
);
#
# I arrange everything in rows and colomns to save space
#
while (<IN>)
{
	chop;
	s/#.*$//o;
	split;
	next if ($#_ < 1);
	$localCode = $_[$column];
	if ($unicodeColumn==-1)
	{
		$uniCode = $_[$#_];
	}
	else
	{
		if ($#_ < $unicodeColumn)
		{
			printf (STDERR "error: file has only %d + 1 colums.\n",
				$#_);
			exit (1);
		}
		$uniCode = $_[$unicodeColumn];
	}

	($leftLocal, $rightLocal) = &getLR ($localCode);
	($leftUni, $rightUni) = &getLR ($uniCode);

	if ($leftUni == 0 && $rightUni==0)
	{
		printf (STDERR "warning: line %d. U+0000\n", $.);
	}
	if ($leftLocal == 0 && $rightLocal ==0)
	{
		printf (STDERR "warning: skipping line %d. Local code is 0\n", $.);
		next;
	}
	if ($shiftNum==1)
	{
		$leftLocal |= 128;
		$rightLocal |= 128;
	}
	if ($shiftNum==-1)
	{
		$leftLocal &= 127;
		$rightLocal &= 127;
	}


	$localMinL = $leftLocal if ($leftLocal < $localMinL);
	$localMinR = $rightLocal if ($rightLocal < $localMinR);

	$localMaxL = $leftLocal if ($leftLocal > $localMaxL);
	$localMaxR = $rightLocal if ($rightLocal > $localMaxR);

	$bigMapLU[$leftLocal * 256 + $rightLocal] = $leftUni*256 + $rightUni;

	$uniMinL = $leftUni if ($leftUni < $uniMinL);
	$uniMinR = $rightUni if ($rightUni < $uniMinR);

	$uniMaxL = $leftUni if ($leftUni > $uniMaxL);
	$uniMaxR = $rightUni if ($rightUni > $uniMaxR);

	$bigMapUL[$leftUni * 256 + $rightUni] = $leftLocal*256 + $rightLocal;
}

close (IN);

if ($binaryMap==1)
{
	@mapLUB = &mapIt ($localMinL, $localMaxL, $localMinR, $localMaxR, @bigMapLU);
	@mapULB = &mapIt ($uniMinL, $uniMaxL, $uniMinR, $uniMaxR, @bigMapUL);

	$start=&packS(16+32+2);
	$head=pack ("a16", "YUDIT-UMAP  1.0");
	$bname=pack ("a32", $alias);
	$localMinLB=&packS($localMinL); $localMaxLB=&packS($localMaxL);
	$localMinRB=&packS($localMinR); $localMaxRB=&packS($localMaxR);
	$uniMinLB=&packS($uniMinL); $uniMaxLB=&packS($uniMaxL);
	$uniMinRB=&packS($uniMinR); $uniMaxRB=&packS($uniMaxR);

	$sizes = $localMinLB . $localMaxLB . $localMinRB . $localMaxRB
		. $uniMinLB . $uniMaxLB . $uniMinRB . $uniMaxRB;

	&fatal unless print OUT $head . $bname. $start. $sizes; 
	&fatal unless print OUT @mapLUB; 
	&fatal unless print OUT @mapULB; 
	exit (0);
}

@mapLU = &mapIt ($localMinL, $localMaxL, $localMinR, $localMaxR, @bigMapLU);
@mapUL = &mapIt ($uniMinL, $uniMaxL, $uniMinR, $uniMaxR, @bigMapUL);

$mapUL = join (' ', @mapUL);
$mapLU = join (' ', @mapLU);

&fatal unless print OUT <<EDO;
/*
 * <<<<<<<<<<< DO NOT EDIT >>>>>>>>>>>>
 * This file is automatically generated.
 * The map was generated from $inputFile
 *
 */

static char umap_name[]="$alias";

/* Decoding local code into unicode. Array Boundaries */
static unsigned short decode_high_min=$localMinL;
static unsigned short decode_high_max=$localMaxL;
static unsigned short decode_low_min=$localMinR;
static unsigned short decode_low_max=$localMaxR;

static unsigned short decode_matrix[]=$mapLU;

/* Encoding unicode. Array Boundaries */
static unsigned short encode_high_min=$uniMinL;
static unsigned short encode_high_max=$uniMaxL;
static unsigned short encode_low_min=$uniMinR;
static unsigned short encode_low_max=$uniMaxR;

static unsigned short encode_matrix[]=$mapUL;

EDO
exit (0);

#
# get the left and the right portion 
#
sub
getLR
{
	local ($number) = $_[0];

	$_ = $_[0];

	if (/^0x([0-9a-zA-Z]+)/)
	{
		$number=0;
		$_=$1;
		while (/([0-9a-zA-Z])(.*)/)
		{
			die "internal error $1" if (!defined ($hexMap{$1}));
			$number = $number * 16 + $hexMap{$1};
			$_ = $2;
		}
	}
	
	local ($left, $right) = (int($number/256),  $number%256);
	return ($left,  $right); 
}

#
# Produce a usable ascii output for the c program.
#
sub
mapIt
{
	local ($minL, $maxL, $minR, $maxR, @array) = @_;
	local ($count) = 0;
	local ($i, $j, $value, $position);
	local ($charsPerRow) = $maxL - $minL + 1;
	local (@retVle);

	$position =0;

	if ($binaryMap==0)
	{
		@retVle = "{";
	}

	for ($i = $minL; $i <= $maxL; $i++)
	{
		for ($j = $minR; $j <= $maxR; $j++)
		{
			$value =  $array[($i << 8) + $j];
			$value=0 if (!defined ($value));
			if ($binaryMap==0)
			{
				push (@retVle, "\n")  if ($position % 8 ==0);
			}
			if ($binaryMap==1)
			{
				push (@retVle, &packS ($value));
			}
			elsif ($value>-10 && $value<10)
			{
				push (@retVle, sprintf ("%d,", $value));
			}
			else
			{
				push (@retVle, sprintf ("0x%x,", $value));
			}
			$position++;
		}
	}
	if ($binaryMap==0)
	{
		push (@retVle, "}");
	}
	return (@retVle);
}

#
# Fatal error handler
#
sub
fatal
{
	close (OUT);
	unlink ($outputFile);
	exit (1);
}

#
# Pack $_[0] into big endian short (16 bit)
#
sub
packS
{
	local ($first) = $_[0]/256;
	local ($second) = $_[0]&0xff;

	return (pack ("C C", $first, $second));
}
