16進ダンプ

指定したファイルを16進ダンプするプログラムを書きました。
Haskell触るようになってから高階関数をより一層多用するようになりました。あとdo || ... endのブロックじゃなくて{|| ... }のブロックを使って、ブロックを一行で書くようになりました。んー、関数型言語脳?
ファイル: hd.rb

#!/usr/bin/env ruby

class String
  require 'enumerator'

  def each_nbytes(n, &block)
    to_enum(:each_byte).each_slice(n, &block)
  end

  def inject_nbytes(init, n)
    ret = init
    each_nbytes(n) {|cs| ret = yield(ret, cs) }
    ret
  end
end

def to_hex(cs)
  cs.inject(' ') {|s, c| s + ' ' + '%02x' % c }
end

def hex_dump(input, offset = 0)
  input.seek(offset)
  while chunk = input.read(16)
    s = '%08x' % offset
    s << chunk.inject_nbytes('', 4) {|r, cs| r + to_hex(cs) }.ljust(52)
    s << '  '
    s << chunk.tr("\x00-\x1f\x7f-\xff", '.')
    puts s
    offset += 16
  end
end

if $0 == __FILE__
  require 'optparse'

  offset = 0
  OptionParser.new do |opt|
    opt.on('-o', '--offset=addr', 'set offset.') do |v|
      offset = case v
               when /^0x/; v.hex
               else;       v.to_i
               end
    end
    opt.parse!(ARGV)
  end
  
  ARGV.each do |file|
    open(file, 'rb') do |input|
      hex_dump(input, offset)
    end
  end
end

ファイル: hd.exy

general:
  startup: hd.rb
  core: cui
  kcode: none

file:
  hd.rb:
  enumerator.so:
    file: C:/Program Files/ruby-1.8/lib/ruby/1.8/i386-mswin32/enumerator.so
    type: extension-library
  optparse.rb:
    file: C:/Program Files/ruby-1.8/lib/ruby/1.8/optparse.rb

ファイル: Rakefile

# -*- ruby -*-

base = 'hd'

require 'rake/clean'
require 'rake/packagetask'

task :default => ["#{base}.exe"]

file "#{base}.exe" => ["#{base}.rb", "#{base}.exy"] do
  sh "exerb.bat #{base}.exy"
  sh "upx #{base}.exe"
end

CLEAN.include("#{base}.exe")

Rake::PackageTask.new(base, '0.1a') do |p|
  p.package_dir = './pkg'
  p.package_files.include('Rakefile')
  p.package_files.include("#{base}.*")
  p.need_zip = true
end

実行例:

> hd.exe hd.exy
00000000  67 65 6e 65  72 61 6c 3a  0d 0a 20 20  73 74 61 72  general:..  star
00000010  74 75 70 3a  20 68 64 2e  72 62 0d 0a  20 20 63 6f  tup: hd.rb..  co
00000020  72 65 3a 20  63 75 69 0d  0a 20 20 6b  63 6f 64 65  re: cui..  kcode
00000030  3a 20 6e 6f  6e 65 0d 0a  0d 0a 66 69  6c 65 3a 0d  : none....file:.
00000040  0a 20 20 68  64 2e 72 62  3a 0d 0a 20  20 65 6e 75  .  hd.rb:..  enu
00000050  6d 65 72 61  74 6f 72 2e  73 6f 3a 0d  0a 20 20 20  merator.so:..
00000060  20 66 69 6c  65 3a 20 43  3a 2f 50 72  6f 67 72 61   file: C:/Progra
00000070  6d 20 46 69  6c 65 73 2f  72 75 62 79  2d 31 2e 38  m Files/ruby-1.8
00000080  2f 6c 69 62  2f 72 75 62  79 2f 31 2e  38 2f 69 33  /lib/ruby/1.8/i3
00000090  38 36 2d 6d  73 77 69 6e  33 32 2f 65  6e 75 6d 65  86-mswin32/enume
000000a0  72 61 74 6f  72 2e 73 6f  0d 0a 20 20  20 20 74 79  rator.so..    ty
000000b0  70 65 3a 20  65 78 74 65  6e 73 69 6f  6e 2d 6c 69  pe: extension-li
000000c0  62 72 61 72  79 0d 0a 20  20 6f 70 74  70 61 72 73  brary..  optpars
000000d0  65 2e 72 62  3a 0d 0a 20  20 20 20 66  69 6c 65 3a  e.rb:..    file:
000000e0  20 43 3a 2f  50 72 6f 67  72 61 6d 20  46 69 6c 65   C:/Program File
000000f0  73 2f 72 75  62 79 2d 31  2e 38 2f 6c  69 62 2f 72  s/ruby-1.8/lib/r
00000100  75 62 79 2f  31 2e 38 2f  6f 70 74 70  61 72 73 65  uby/1.8/optparse
00000110  2e 72 62 0d  0a                                     .rb..