#!/usr/local/bin/perl
#
# $Id: ebcdic2ascii.pl,v 1.1.1.1 2002/03/01 21:50:52 valerio Exp $
#
# This script is copyrighted
# Copyright (c) 2002 Valerio Di Giampietro
# Valerio@DiGiampietro.com
#
# All rights reserved. This program is free software; you can
# redistribute it and/or modify it under the same terms as Perl
# itself.
#
#
#
# $Log: ebcdic2ascii.pl,v $
# Revision 1.1.1.1  2002/03/01 21:50:52  valerio
# Imported sources
#
#
#
use Getopt::Std;
use Convert::EBCDIC;

$translator = new Convert::EBCDIC;


$debug=0;
$status=0;
#======================================================================
# data related to file.layout format; a tipical row has the following
# format:
#
# field      field description                  type  len dec.   len   start end
# name                                                log        phy 
# ITNBR      ITEM NUMBER                          A    15         15      1   15
#
# each array has 2 element the starting row and the length of related
# field
#======================================================================
@campo=(0,10);        #field name
@descr=(11,35);       #field description
@dacol=(70,4);        #from column
@len =(63,4);         #field length in bytes
@loglen = (52,4);     #field logical length
@type=(49,1);         #field type
@decimals=(56,3);     #number of decimals
#
#======================================================================
# packed2ascii   converts a packed decimal to ascii
#                input parameters:
#                   $str       the packed decimal string
#                   $decimals  number of decimals
# example: $str=0x123456d; $decimals=2;
#          packed2asci($str,$decimals) would return -1234.56
#======================================================================
# 
sub packed2ascii {
    my $decimals=$_[1];
    my $str=unpack("H*",$_[0]);
    if ($debug > 2) {
	print STDERR "===> packed2ascii  input str: ", uc $str,"\n";
	print STDERR "                    decimals: $decimals\n";
    }
    my $n;            
    my $sign=chop $str;
    if ($decimals > 0) {
	$str=substr($str,0,-$decimals) . '.' . substr($str,-$decimals);
	$n= $str + 0.0;
    } else {
	$n= $str + 0;
    }
    if ($sign eq 'd') {
	$n= -$n;
    }
    if ($decimalpoint ne '.') {
	$n=~s/\./$decimalpoint/;
    }
    if ($debug > 2) {
	print STDERR "                    coverted: $n\n";
    }
    return $n;
}
#
#======================================================================
# signed2ascii   converts asigned decimal to ascii
#                input parameters:
#                   $str       the signed decimal string
#                   $decimals  number of decimals
#
# example: $str=0xf1f2f3f4d5; $decimals=2;
#          packed2asci($str,$decimals) would return -1234.56
#======================================================================
# 
sub signed2ascii {
    my $decimals=$_[1];
    my $str=unpack("H*",$_[0]);
    if ($debug > 2) {
	print STDERR "===> signed2ascii  input str: ", uc $str,"\n";
	print STDERR "                    decimals: $decimals\n";
    }
    $str=~s/f//g;
    my $n;
    if ($str=~s/d//g) {
	$sign='d';
    } else {
	$sign='c';
	$str=~s/c//g;
    }
    if ($decimals > 0) {
	$str=substr($str,0,-$decimals) . '.' . substr($str,-$decimals);
	$n= $str + 0.0;
    } else {
	$n= $str + 0;
    }
    if ($sign eq 'd') {
	$n= -$n;
    }
    if ($decimalpoint ne '.') {
	$n=~s/\./$decimalpoint/;
    }
    if ($debug > 2) {
	print STDERR "                    coverted: $n\n";
    }
    return $n;
}
#======================================================================
# autocrop strips leading and trailing spaces from a string
#     input parameter
#           $str   string
#     returnd value
#           $str   with leading and trailing spaces tripped
#======================================================================
sub autocrop {
    my $s=$_[0];
    $s=~s/^\s*//;
    $s=~s/\s*$//;
    return $s;
}
#======================================================================
# usage  print usage message and exit
#======================================================================
sub usage {
    print "Usage: $0 [-s c] [-d lev] [-f|-b] file.layout file.ebcdic\n";
    print "   -d lev     set debug level\n";
    print "   -f         use field names instead of descriptions\n";
    print "   -b         use both field names and descriptions\n";
    print "   -s c       use c as field separator (default is '|')\n";
    print "   -a         no '.' -> ',' translation for decimal point\n";
    exit;
}
#
#======================================================================
# main program 
#======================================================================
#
getopts('d:s:fba');
$decimalpoint=",";  #default value (here in Italy) for the decimal point
if ($opt_a) {
    $decimalpoint=".";
}

$csep = $opt_s || "|";
if (defined $opt_d) {
    $debug=$opt_d;
}

if ($#ARGV < 1) {
    usage();
}

$ftracciato=$ARGV[0];
$fdati=$ARGV[1];
$dirtracciati="/prj/as400imm/formats2";
if (not -e $ftracciato) {
    $ftracciato="$dirtracciati/$ftracciato";
}
print "ftracciato: $ftracciato\n" if $debug;
print "fdati:      $fdati\n" if $debug;

#======================================================================
# read the layout file and fill in related data structure
#======================================================================
open(FTRA,$ftracciato) || die "Error opening $ftracciato\n";
$status=2;
while (<FTRA>) {
    if (/^\s*-+\s*$/) {
	$status++;
	print "# status: $status\n" if $debug;
    } else {
	if ($status==2) {
	    $campo=lc autocrop(substr $_, $campo[0], $campo[1]);
	    $descr=autocrop(substr $_, $descr[0], $descr[1]);
	    $dacol=autocrop(substr $_, $dacol[0], $dacol[1]) - 1;
	    $len =autocrop(substr $_, $len[0],  $len[1]);
	    $loglen =autocrop(substr $_, $loglen[0],  $loglen[1]);
	    $type=substr $_, $type[0],$type[1];
	    $decimals=substr $_, $decimals[0],$decimals[1];
	    $dacol{$campo}=$dacol;
	    $len{$campo}=$len || $loglen;
	    if ($loglen > $len) {
		$len{$campo}=$loglen if ($type ne 'P');
	    }
	    $descr{$campo}=$descr;
	    $type{$campo}=$type;
	    $decimals{$campo}=$decimals;
	    push @campi,$campo;
	    print "# $campo ($descr{$campo},$dacol{$campo},$len{$campo},",
                             "$type{$campo},$decimals{$campo})\n"
		if $debug;
	}
    }
}

print "--- Second part\n" if $debug;
print "---campi: @campi\n" if $debug;

@outcampi=@campi;


$totlen=0;
for $i (@outcampi) {
    $dscr=$descr{$i} || $i;
    if ($opt_f) {
	print "$i",$csep;
    } elsif ($opt_b) {
	print "$i: $dscr",$csep;
    }
    else {
	print "$dscr",$csep;
    }
    $totlen = $totlen + $len{$i};
    print "  -> $i ($totlen= $totlen)\n" if $debug;
}
print "\n";
print "-->Total record length = $totlen \n\n" if $debug;


#======================================================================
# process the ebcdic file
#======================================================================

open (FDAT,$ARGV[1]) || die "error opening $ARGV[1]\n";

while (read(FDAT,$_,$totlen)) {
    
    ################## fill in the %s hash 
    for $i (@campi) {
	$sebcdic=substr $_,$dacol{$i},$len{$i};

	if ($type{$i} eq 'P') {               #### Packed field
	    $s=packed2ascii($sebcdic,$decimals{$i});
	} elsif ($type{$i} eq 'S') {          #### Signed field
	    $s=signed2ascii($sebcdic,$decimals{$i});
	} else {                              #### Normal field
	    $sascii=$translator->toascii($sebcdic);
	    $s=autocrop($sascii);
	}
	$s{$i}=$s;
    }
    ################ printout the %s hash;

    for $i (@outcampi) {
	print $s{$i},$csep;
    }
    print "\n";
    
}

	    
	
    

