First ruby code, need hint on iterator

Hello,

Consider the following code which generates a hexdump of a string:


#!/usr/bin/ruby

module Dump

    def hexdump

            x = 0
            offset = 0
            hex = ""
            str = ""
            out = ""

            each_byte { |c|

                    x = x + 1

                    hex << sprintf("%02x ", c)
                    hex << "- " if(x == 8)
                    str << ((c >= 32 && c<=127) ? c.to_i.chr : ".")

                    if(x == 16)
                            out << sprintf("%08x: %-50s %s\n", 

offset, hex, str)
x = 0
hex = “”
str = “”
offset = offset + 16
end
}

            out << "\n"

            return out
    end

end

l = $stdin.read(10000)
l.extend Dump
print l.hexdump


This program has a serious flaw: only if 16 bytes are collected from the
input,
a new line with hex codes is printed. If the input string has a length
that is
not a multiple of 16, the remaining bytes will not be handled.

A solution would be to duplicate the line

out << sprintf("%08x: %-50s %s\n", offset, hex, str)

somewhere at the end of the loop, so that any remaining buffers are
printed.
This forces me to duplicate code, though, which is not what I want.

The obvious solution for me would be to change the line

if(x == 16)

to something like

if((x == 16) || (c.is_the_last_element_from_the_set))

The problem is in the fictional thingy ‘is_the_last_element_from_the
set’,
which I believe is not available.

What would be the idiomatic solution for this in Ruby ? Any other
comments on
the code are welcome as well, ofcourse

Thank you

This program has a serious flaw: only if 16 bytes are collected from the input,
a new line with hex codes is printed. If the input string has a length that is
not a multiple of 16, the remaining bytes will not be handled.

A solution would be to duplicate the line

    out << sprintf("%08x: %-50s %s\n", offset, hex, str)

I think it’s ok to duplicate a single line. If you are worried about
the two lines
getting out of sync, put the line in a function:

def printHex(out, offset, hex, str)
out << sprintf("%08x: %-50s %s\n", offset, hex, str)
end

Keep a count of total characters processed, and output if that is the
same as the length of your string: (see my embedded changes)

Gerr wrote:

    def hexdump

            x = 0
               num_chars = 0
            offset = 0
            hex = ""
            str = ""
            out = ""

            each_byte { |c|

                    x = x + 1
                       num_chars += 1
                    hex << sprintf("%02x ", c)
                    hex << "- " if(x == 8)
                    str << ((c >= 32 && c<=127) ? c.to_i.chr : ".")
                     if(x == 16) || num_chars >= length

On 7/17/06, Gerr [email protected] wrote:

Hello,

Consider the following code which generates a hexdump of a string:

What would be the idiomatic solution for this in Ruby ? Any other comments on
the code are welcome as well, ofcourse

If you want to do things with 16 bytes at a time, you might as well
process them in groups of 16:

require ‘enumerator’
module Dump
def hexdump
offset = 0
out = ‘’
split(‘’).each_slice(16) {|chars|
hc = chars.map{|c| “%02x " % c[0] }
hex = hc[0…7] << '- ’ << hc[8…15]
str = chars.map{|c| (c[0] >= 32 && c[0] <= 127) ? c : “.” }
out << sprintf(”%08x: %-50s %s\n", offset, hex, str)
offset += 16
}
return out;
end
end

or even:

module Dump
def hexdump
offset = -16
split(‘’).enum_slice(16).map {|chars|
hc = chars.map{|c| “%02x " % c[0] }
hex = hc[0…7] << '- ’ << hc[8…15]
str = chars.map{|c| (c[0] >= 32 && c[0] <= 127) ? c : “.” }
sprintf(”%08x: %-50s %s\n", offset += 16, hex, str)
}.join
end
end

Sander L. [email protected] wrote:

     offset += 16
   }
   return out;

end
end

Delightful ! It’s hard to think outside the box if you mainly have been
programming C for 20 years…

Thank you very much, I will learn a lot from this newsgroup, I’m sure
:slight_smile: