Skip to content

Instantly share code, notes, and snippets.

@no6v
Created April 26, 2009 00:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save no6v/101824 to your computer and use it in GitHub Desktop.
Save no6v/101824 to your computer and use it in GitHub Desktop.
cat(1)
#!ruby1.9
# -*- coding: us-ascii -*-
Encoding.default_external = "ASCII-8BIT"
require "optparse"
def squeeze_blank
re = /\A\Z/
lfd = 0
->(block) do
block.replace(
block.lines.map{|line|
line.tap{
if re === line
lfd += 1
line.clear if lfd > 1
else
lfd = 0
end
}} * "")
end
end
def show_tabs
re = /\t/
f = "^I"
->(block){block.gsub!(re){f}}
end
def show_nonprinting
re1 = /[\x00-\x08\x0b-\x1f\x7f]+/
re2 = /[\x80-\x9f]+/
re3 = /[\xa0-\xfe]+/
re4 = /[\xff]+/
->(block) do
block.gsub!(re1) do |m|
"^" + m.bytes.map{|b| (b ^ 0x40).chr} * "^"
end
block.gsub!(re2) do |m|
"M-^" + m.bytes.map{|b| (b - 0x40).chr} * "M-^"
end
block.gsub!(re3) do |m|
"M-" + m.bytes.map{|b| (b ^ 0x80).chr} * "M-"
end
block.gsub!(re4) do |m|
"M-^?" * m.size
end
end
end
def number
re = /^/
f = "%6d\t"
n = 0
->(block){block.gsub!(re){f % (n += 1)}}
end
def number_nonblank
re = /^(?!$)/
f = "%6d\t"
n = 0
->(block){block.gsub!(re){f % (n += 1)}}
end
def show_ends
re = /$\n/
f = "$\n"
->(block){block.gsub!(re){f}}
end
def adjust(filters)
order = [:squeeze_blank, :show_tabs, :show_nonprinting, :number, :number_nonblank, :show_ends]
filters.tap{|f|
f.uniq!
f.delete(:number) if f.include?(:number_nonblank)
}.sort_by(&order.method(:index))
end
def parse_options(argv)
op = OptionParser.new
op.banner = <<BANNER
Usage: cat [OPTION]... [FILE]...
Concatenate FILE(s), or standard input, to standard output.
BANNER
filters = []
op.on("-A", "--show-all", "equivalent to -vET"){argv.unshift(*["-v", "-E", "-T"])}
op.on("-b", "--number-nonblank", "number nonempty output lines"){filters << :number_nonblank}
op.on("-e", "equivalent to -vE"){argv.unshift(*["-v", "-E"])}
op.on("-E", "--show-ends", "display $ at end of each line"){filters << :show_ends}
op.on("-n", "--number", "number all output lines"){filters << :number}
op.on("-s", "--squeeze-blank", "suppress repeated empty output lines"){filters << :squeeze_blank}
op.on("-t", "equivalent to -vT"){argv.unshift(*["-v", "-T"])}
op.on("-T", "--show-tabs", "display TAB characters as ^I"){filters << :show_tabs}
op.on("-u", "(ignored)"){}
op.on("-v", "--show-nonprinting", "use ^ and M- notation, except for LFD and TAB"){filters << :show_nonprinting}
op.parse!(argv)
adjust(filters).map!(&method(:__send__))
end
filters = parse_options(ARGV)
while block = ARGF.read(1024)
filters.each{|filter| filter[block]}
print block
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment