On May 10, 2007, at 12:39 PM, Todd Burch wrote:

> Here a whole program that illlustrates the error.  I'm running under
> Windows Ruby 1.8.5.  (it's ugly and chopped up, but it works... er...
> doesn't work... er...  you know what I mean)
>
> Todd

First, damn you for getting me interested in this ;-)

Here's a whole program (with a couple tests!) that uses an array to  
map from an EBCDIC index to a single character ASCII string (easier  
to construct than the character value).

I hope you find some useful idioms in there.

-Rob

Rob Biedenharn		http://agileconsultingllc.com
Rob / AgileConsultingLLC.com


#!/usr/bin/env ruby -w
#
# Ruby program to convert a z/OS EBCDIC to ASCII.
#

class Record
   EBCDIC_TO_ASCII = Array.new(256) # the EBCDIC position holds the  
ASCII value

   EBCDIC_TO_ASCII[0x40] = ' '

   EBCDIC_TO_ASCII[0x81..0x89] = [*'a'..'i']
   EBCDIC_TO_ASCII[0x91..0x99] = [*'j'..'r']
   EBCDIC_TO_ASCII[0xA2..0xA9] = [*'s'..'z']
   EBCDIC_TO_ASCII[0xC1..0xC9] = [*'A'..'I']
   EBCDIC_TO_ASCII[0xD1..0xD9] = [*'J'..'R']
   EBCDIC_TO_ASCII[0xE2..0xE9] = [*'S'..'Z']

   EBCDIC_TO_ASCII[0x4B] = '.'
   EBCDIC_TO_ASCII[0x4C] = '<'
   EBCDIC_TO_ASCII[0x4D] = '('
   EBCDIC_TO_ASCII[0x4E] = '+'
   EBCDIC_TO_ASCII[0x4F] = '|'
   EBCDIC_TO_ASCII[0x50] = '&'

   EBCDIC_TO_ASCII[0x5A] = '!'
   EBCDIC_TO_ASCII[0x5B] = '$'
   EBCDIC_TO_ASCII[0x5C] = '*'
   EBCDIC_TO_ASCII[0x5D] = ')'
   EBCDIC_TO_ASCII[0x5E] = ';'
   EBCDIC_TO_ASCII[0x5F] = '^'
   EBCDIC_TO_ASCII[0x60] = '-'
   EBCDIC_TO_ASCII[0x61] = '/'

   EBCDIC_TO_ASCII[0x6B] = ','
   EBCDIC_TO_ASCII[0x6C] = '%'
   EBCDIC_TO_ASCII[0x6D] = '_'
   EBCDIC_TO_ASCII[0x6E] = '>'
   EBCDIC_TO_ASCII[0x6F] = '?'
   EBCDIC_TO_ASCII[0X79] = '`'
   EBCDIC_TO_ASCII[0x7A] = ':'
   EBCDIC_TO_ASCII[0x7B] = '#'
   EBCDIC_TO_ASCII[0x7C] = '@'
   EBCDIC_TO_ASCII[0x7D] = '\''
   EBCDIC_TO_ASCII[0x7E] = '='
   EBCDIC_TO_ASCII[0x7F] = '"'
   EBCDIC_TO_ASCII[0xBA] = '['
   EBCDIC_TO_ASCII[0xBB] = ']'
   EBCDIC_TO_ASCII[0xC0] = '{'
   EBCDIC_TO_ASCII[0xD0] = '}'
   EBCDIC_TO_ASCII[0xE0] = '\\'

   EBCDIC_TO_ASCII[0xF0..0xF9] = [*'0'..'9']

   def self.to_ascii str
     str.split(//).map {|e| EBCDIC_TO_ASCII[e[0]] || 0.chr }.join
   end

   #  This Record.to_h() method converts a hex byte into a  
displayable, human
   #  readable value.  i.e. X'F5' to "F5".
   #
   def self.to_h str, chunk=32
     str.unpack('H*').first.scan(/.{2,#{2*chunk}}/).join("\n")
   end

   #
   # This method called to dump the data in hex format.
   #
   def self.dump_area data, chunk=16
     fsize = data.size
     lines,last = fsize.divmod(chunk)    # get # of full lines and  
figure the remainder.
     i = 0
     lines.downto(0) do
       str = data[i,chunk]
       hexdata = str.unpack('H*').first.scan(/.{2,8}/).join(" ")  
#.upcase
       printf "%08X  %s  %s\n", i, hexdata, to_ascii(str).tr("\000- 
\037\177-\377",'.')
       i += chunk
     end
   end
end


if __FILE__ == $0
   require 'test/unit'

   puts "EBCDIC Table"
   Record.dump_area((0...Record::EBCDIC_TO_ASCII.size).map{|e|  
e.chr}.join)

   class EbcdicTest < Test::Unit::TestCase
     def setup
       @instring_ascii = "AB>AA<AC"
       # EBCDIC for "AB>AA<AC"
       @instring_ebcdic = 0XC1.chr + 0xC2.chr + 0x6E.chr + 0xC1.chr +  
0xC1.chr + 0x4C.chr + 0xC1.chr + 0xC3.chr
     end

     def test_simple
       assert_equal @instring_ascii, Record.to_ascii(@instring_ebcdic)
     end
     def test_numbers
       @expected = "$1,234.95"
       #            $     1     ,     2     3     4     .     9     5
       @input = [0x5B, 0xF1, 0x6B, 0xF2, 0xF3, 0xF4, 0x4B, 0xF9,  
0xF5].map {|e| e.chr}.join
       assert_equal @expected, Record.to_ascii(@input)
     end
   end
end
__END__