#!/usr/local/bin/perl
##         universal cyrillic decoder
##---------------------------------------------------------------------------##
##  Copyright (C) 1995: Ilya Sandler isandler@utkux.utcc.utk.edu
##  This program is free software; you can redistribute it and/or modify
##  it under the terms of the GNU General Public License.
##  THERE IS NO WARRANTY OF ANY KIND. USE IT AT YOUR OWN RISK.
##---------------------------------------------------------------------------##
##  cyrcode   is a Perl program to convert between different
## cyrillic encodings, cyrcode uses external encoding table cyrtab.
## The program reads standard input and writes to standard output
## usage:
## cyrcode.pl from to
## where from and to are names of encoding tables
## note table names should coincide with those indicated in cyrtab
##--------------------------------------------------------

open(dat,'cyrtab') || die "unable to open 'cyrtab'";
@names=&readnext;

if (($ARGV[0] eq "-help") || ($#ARGV < 1)){
    print "Universal cyrillic decoder \n";
    print "usage: \n  cyrcode.pl from to <infile >outfile";
    print "\n where 'from' and 'to' are the names of encoding tables \n";
    print "currently supported tables are: ", join(", ",@names), "\n" ;
    print "Example:    cyrcode.pl koi8 alt < file1.txt \n" ;
    print "converts file.txt from 'koi8' to 'alt' and writes the result to ";
    print "standard output \n";
    exit;
}

#ignore cases
$ARGV[0] =~ y/A-Z/a-z/;
$ARGV[1] =~ y/A-Z/a-z/;
$from=$to=-1;

for ($i=0; $i <= $#names; $i++) {
    $names[$i]=~ y/A-Z/a-z/;
    if (index($ARGV[0],$names[$i]) >=0) {$from=$i;}
    if (index($ARGV[1], $names[$i]) >=0) {$to=$i;};
}

if (($from == -1) || ($to == -1)) {
    print "unknown encoding table name \n";
    print "known table names:",join(', ',@names),"\n";
    exit;
}

#initialize decoding table
for ($i = 0; $i < 256; $i++) {$decode[$i]=pack("cc",$i)};
while (!eof(dat)){
    @m=&readnext;

    if ($m[0] eq "") {last;}

    if( $m[$from] =~ /^0x/ )
    {
       $m[$from] = hex $m[$from];
    }

    if( $m[$to] =~ /^0x/ )
    {
#       print "t";
       $m[$to] = hex $m[$to] 
    }

    if ($m[$from]=~ tr/a-z//){
        print "can not convert from ", $names[$from],"\n";
        exit;
    }
    if ($m[$to]=~tr/a-zA-Z\'\"//)
    {
#       $decode[$m[$from]]=$m[$to];
       $decode{$m[$from]}=$m[$to];
    }
    else
    {  
       $decode{$m[$from]}=pack("cc",$m[$to]);
    }
};



#actual convertion is here
while (!eof(STDIN)){
   $code = getUTFChar();
   $ch = $decode{$code};
   print $ch if $ch;
   print sprintf "%c", $code unless $ch;
};

sub getUTFChar
{
   my($ch);
   my($i);
   my($numBytes);


   $ch = ord(getc);
   $numBytes = getNumBytes($ch);
   $octets = ( ($ch << $numBytes) & hex("00FF") ) >> $numBytes;
   for( $i=1; $i<$numBytes; $i++ )
   {
      $ch = ord(getc);
      $ch = ($ch << 2) & hex("00FF");
      $temp = sprintf "%x%02x",$octets,$ch; 
      $octets = (hex $temp) >> 2;
   }
 
   $temp = sprintf "%x", $octets;
   $temp =~ tr/a-f/A-F/; 
   return hex $temp;
}

sub isUSASCI
{
   my( $ch ) = @_;

   return (getNumBytes($ch) == 0 ) ;
}

sub getNumBytes($ch)
{
   my( $ch ) = @_;
   my( $counter, $hb ) = 0;

   $hb = getHiBit($ch);
   while( $hb == 1 )
   {
      $counter++;
      $ch = $ch << 1;
      $hb = getHiBit($ch);
   }

#   print " $counter bytes found \n";
   return $counter;
}

sub getHiBit
{
   my( $ch ) = @_;

#   print "   \&: ".($ch & 128)." ";

   return (($ch & 128) == 128);
}
exit 0;

# subprograms----------------------
sub readnext {
    local($str)='';
    while ((!eof(dat))&&($str eq '')){
        $str=<dat>;
        $str=~ s/\n//g;   #strips \n
        $str=~ s/^[\ \t]+//g;   #strips leading white space
        $str=~ s/#[\0-\377]+//g;  #strips comment
   }
    split(/[\ \t]+/,$str);
}
