Here is my partial solution for the Quoted Printable quiz. I'm still
pretty new to Ruby, so it took me a while to get what you see here. I
think the only thing I didn't get to adding was line length checks.
#!/usr/bin/env ruby
···
#
# TODO:
# - Limit lines to LINE_MAX_LENGTH during encoding.
require 'optparse'
# Global constants
XML_ENTITIES = %w(< > &)
LINE_END_PAIR = "\r\n"
LINE_CONTINUATION = "=\r\n"
LINE_MAX_LENGTH = 76
class String
def qp_decode()
result = ''
# output portions of line, alternating normal text and encoded bytes
left = 0
while right = index('=', left) do
result << slice(left ... right) # if right > left
result << qp_decode_byte( slice(right, 3) )
left = right + 3
end
# add remainder of line
result << slice(left .. -1) if slice(left)
# finished
result
end
def qp_encode(handleXmlEntities)
# preserve trailing whitespace for later
trimmed = rstrip
trail_ws = slice(trimmed.length .. -1)
# encode characters on line
result = ''
trimmed.each_byte do |c|
if handleXmlEntities and XML_ENTITIES.include?(c.chr)
result << qp_encode_byte(c)
else
case c
when 9, 32..60, 62..126
result << c
else
result << qp_encode_byte(c)
end
end
end
# append trailing whitespace
trail_ws.each_byte { |c| result << qp_encode_byte(c) }
# finished
result
end
def qp_decode_byte(s)
s[1..-1].to_i(16)
end
def qp_encode_byte(c)
'=' + (c < 10 ? '0' : '') + c.to_s(16).upcase
end
private :qp_decode_byte, :qp_encode_byte
end
class IO
def qp_decode
each_line { |line| $stdout.puts line.chomp.qp_decode } #
outputs native eol
end
def qp_encode(xmlEncode)
each_line { |line| $stdout << line.chomp.qp_encode(xmlEncode)
<< LINE_END_PAIR }
end
end
class QuotedPrintable
def process(file)
@decode ? file.qp_decode : file.qp_encode(@xmlEncode)
end
attr_writer :decode, :xmlEncode
end
# Main code from here down...
qp = QuotedPrintable.new
# Option Processing
opts = OptionParser.new
opts.on('-x') { qp.xmlEncode = true }
opts.on('-d') { qp.decode = true }
files = opts.parse(ARGV)
# File Processing
files.collect! { |f| File.new(f) }
files = [$stdin] if files.empty?
files.each { |f| qp.process(f) }
--
Matthew Moss <matthew.moss@gmail.com>