rbkb 0.6.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +74 -0
- data/README.rdoc +149 -0
- data/Rakefile +47 -0
- data/bin/b64 +5 -0
- data/bin/bgrep +5 -0
- data/bin/blit +5 -0
- data/bin/c +5 -0
- data/bin/crc32 +5 -0
- data/bin/d64 +5 -0
- data/bin/dedump +5 -0
- data/bin/feed +5 -0
- data/bin/hexify +5 -0
- data/bin/len +5 -0
- data/bin/plugsrv +271 -0
- data/bin/rex +10 -0
- data/bin/rstrings +5 -0
- data/bin/slice +5 -0
- data/bin/telson +5 -0
- data/bin/unhexify +5 -0
- data/bin/urldec +5 -0
- data/bin/urlenc +5 -0
- data/bin/xor +5 -0
- data/cli_usage.rdoc +285 -0
- data/doctor-bag.jpg +0 -0
- data/lib/rbkb.rb +51 -0
- data/lib/rbkb/cli.rb +219 -0
- data/lib/rbkb/cli/b64.rb +35 -0
- data/lib/rbkb/cli/bgrep.rb +86 -0
- data/lib/rbkb/cli/blit.rb +89 -0
- data/lib/rbkb/cli/chars.rb +24 -0
- data/lib/rbkb/cli/crc32.rb +35 -0
- data/lib/rbkb/cli/d64.rb +28 -0
- data/lib/rbkb/cli/dedump.rb +52 -0
- data/lib/rbkb/cli/feed.rb +229 -0
- data/lib/rbkb/cli/hexify.rb +65 -0
- data/lib/rbkb/cli/len.rb +76 -0
- data/lib/rbkb/cli/rstrings.rb +108 -0
- data/lib/rbkb/cli/slice.rb +47 -0
- data/lib/rbkb/cli/telson.rb +87 -0
- data/lib/rbkb/cli/unhexify.rb +50 -0
- data/lib/rbkb/cli/urldec.rb +35 -0
- data/lib/rbkb/cli/urlenc.rb +35 -0
- data/lib/rbkb/cli/xor.rb +43 -0
- data/lib/rbkb/extends.rb +725 -0
- data/lib/rbkb/http.rb +21 -0
- data/lib/rbkb/http/base.rb +172 -0
- data/lib/rbkb/http/body.rb +214 -0
- data/lib/rbkb/http/common.rb +74 -0
- data/lib/rbkb/http/headers.rb +370 -0
- data/lib/rbkb/http/parameters.rb +104 -0
- data/lib/rbkb/http/request.rb +58 -0
- data/lib/rbkb/http/response.rb +86 -0
- data/lib/rbkb/plug.rb +9 -0
- data/lib/rbkb/plug/blit.rb +222 -0
- data/lib/rbkb/plug/cli.rb +83 -0
- data/lib/rbkb/plug/feed_import.rb +74 -0
- data/lib/rbkb/plug/peer.rb +67 -0
- data/lib/rbkb/plug/plug.rb +215 -0
- data/lib/rbkb/plug/proxy.rb +26 -0
- data/lib/rbkb/plug/unix_domain.rb +75 -0
- data/lib_usage.rdoc +176 -0
- data/rbkb.gemspec +38 -0
- data/spec/rbkb_spec.rb +7 -0
- data/spec/spec_helper.rb +16 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +292 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- data/test/test_cli_b64.rb +35 -0
- data/test/test_cli_bgrep.rb +137 -0
- data/test/test_cli_blit.rb +11 -0
- data/test/test_cli_chars.rb +21 -0
- data/test/test_cli_crc32.rb +108 -0
- data/test/test_cli_d64.rb +22 -0
- data/test/test_cli_dedump.rb +118 -0
- data/test/test_cli_feed.rb +11 -0
- data/test/test_cli_helper.rb +96 -0
- data/test/test_cli_hexify.rb +63 -0
- data/test/test_cli_len.rb +96 -0
- data/test/test_cli_rstrings.rb +15 -0
- data/test/test_cli_slice.rb +73 -0
- data/test/test_cli_telson.rb +11 -0
- data/test/test_cli_unhexify.rb +43 -0
- data/test/test_cli_urldec.rb +50 -0
- data/test/test_cli_urlenc.rb +44 -0
- data/test/test_cli_xor.rb +71 -0
- data/test/test_helper.rb +5 -0
- data/test/test_http.rb +27 -0
- data/test/test_http_helper.rb +60 -0
- data/test/test_http_request.rb +136 -0
- data/test/test_http_response.rb +222 -0
- data/test/test_rbkb.rb +19 -0
- metadata +238 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'rbkb/cli'
|
2
|
+
|
3
|
+
# Copyright 2009 emonti at matasano.com
|
4
|
+
# See README.rdoc for license information
|
5
|
+
#
|
6
|
+
# The hexify command converts a string or raw data to hex characters.
|
7
|
+
# Input can be supplied via stdin, a string argument, or a file (with -f).
|
8
|
+
class Rbkb::Cli::Hexify < Rbkb::Cli::Executable
|
9
|
+
def make_parser
|
10
|
+
super()
|
11
|
+
add_std_file_opt(:indat)
|
12
|
+
arg = @oparse
|
13
|
+
|
14
|
+
# Add local options
|
15
|
+
arg.banner += " <data | blank for stdin>"
|
16
|
+
|
17
|
+
arg.on("-l", "--length LEN", Numeric, "Output lines of LEN bytes") do |l|
|
18
|
+
@opts[:len] = l
|
19
|
+
end
|
20
|
+
|
21
|
+
arg.on("-d", "--delim=DELIMITER", "DELIMITER between each byte") do |d|
|
22
|
+
@opts[:delim] = d
|
23
|
+
end
|
24
|
+
|
25
|
+
arg.on("-p", "--prefix=PREFIX", "PREFIX before each byte") do |p|
|
26
|
+
@opts[:prefix] = p
|
27
|
+
end
|
28
|
+
|
29
|
+
arg.on("-s", "--suffix=SUFFIX", "SUFFIX after each byte") do |s|
|
30
|
+
@opts[:suffix] = s
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def parse(*args)
|
35
|
+
super(*args)
|
36
|
+
|
37
|
+
# blackbag-style space delimiter compatability
|
38
|
+
if @argv[0] == "+" and @opts[:delim].nil?
|
39
|
+
@opts[:delim]=" "
|
40
|
+
@argv.shift
|
41
|
+
end
|
42
|
+
|
43
|
+
parse_string_argument(:indat)
|
44
|
+
parse_catchall()
|
45
|
+
end
|
46
|
+
|
47
|
+
def go(*args)
|
48
|
+
super(*args)
|
49
|
+
|
50
|
+
# Default to standard input
|
51
|
+
@opts[:indat] ||= @stdin.read()
|
52
|
+
|
53
|
+
indat = @opts.delete(:indat)
|
54
|
+
len = (@opts.delete(:len) || indat.length)
|
55
|
+
|
56
|
+
bail("Length must be greater than zero") unless(len > 0)
|
57
|
+
|
58
|
+
until (m = indat.slice!(0..len-1)).empty?
|
59
|
+
@stdout << m.hexify(@opts)
|
60
|
+
@stdout.puts((opts[:delim] and ! indat.empty?)? opts[:delim] : "\n")
|
61
|
+
end
|
62
|
+
self.exit(0)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
data/lib/rbkb/cli/len.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'rbkb/cli'
|
2
|
+
|
3
|
+
# Copyright 2009 emonti at matasano.com
|
4
|
+
# See README.rdoc for license information
|
5
|
+
|
6
|
+
# len prepends a binary length number in front of its input and outputs
|
7
|
+
# raw on STDOUT
|
8
|
+
class Rbkb::Cli::Len < Rbkb::Cli::Executable
|
9
|
+
|
10
|
+
def initialize(*args)
|
11
|
+
# endianness pair. index 0 is always the default
|
12
|
+
@endpair = [:big, :little]
|
13
|
+
|
14
|
+
super(*args) do |this|
|
15
|
+
{
|
16
|
+
:nudge => 0,
|
17
|
+
:size => 4,
|
18
|
+
:endian => @endpair[0],
|
19
|
+
}.each {|k,v| this.opts[k] ||= v}
|
20
|
+
|
21
|
+
yield this if block_given?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def make_parser()
|
26
|
+
super()
|
27
|
+
add_std_file_opt(:indat)
|
28
|
+
arg = @oparse
|
29
|
+
arg.banner += " <data | blank for stdin>"
|
30
|
+
|
31
|
+
arg.on("-n", "--nudge INT", Numeric, "Add integer to length") do |n|
|
32
|
+
@opts[:nudge] += n
|
33
|
+
end
|
34
|
+
|
35
|
+
arg.on("-s", "--size=SIZE", Numeric,
|
36
|
+
"Size of length field in bytes") do |s|
|
37
|
+
bail("Size must be greater than 0") unless (@opts[:size] = s) > 0
|
38
|
+
end
|
39
|
+
|
40
|
+
arg.on("-x", "--[no-]swap",
|
41
|
+
"Swap endianness. Default=#{@opts[:endian]}") do |x|
|
42
|
+
@opts[:endian] = @endpair[(x)? 1 : 0]
|
43
|
+
end
|
44
|
+
|
45
|
+
arg.on("-t", "--[no-]total", "Include size word in size") do |t|
|
46
|
+
@opts[:tot]=t
|
47
|
+
end
|
48
|
+
|
49
|
+
arg.on("-l", "--length=LEN", Numeric,
|
50
|
+
"Ignore all other flags and use static LEN") do |l|
|
51
|
+
@opts[:static]=l
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
def parse(*args)
|
57
|
+
super(*args)
|
58
|
+
@opts[:indat] ||= @argv.shift
|
59
|
+
parse_catchall()
|
60
|
+
@opts[:indat] ||= @stdin.read
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def go(*args)
|
65
|
+
super(*args)
|
66
|
+
unless len=@opts[:static]
|
67
|
+
len = @opts[:indat].size
|
68
|
+
len += @opts[:size] if @opts[:tot]
|
69
|
+
len += @opts[:nudge]
|
70
|
+
end
|
71
|
+
@stdout << len.to_bytes(@opts[:endian], @opts[:size]) << @opts[:indat]
|
72
|
+
self.exit(0)
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'rbkb/cli'
|
2
|
+
|
3
|
+
# Copyright 2009 emonti at matasano.com
|
4
|
+
# See README.rdoc for license information
|
5
|
+
#
|
6
|
+
# rstrings is Unix "strings" in ruby... with some extra stuff
|
7
|
+
class Rbkb::Cli::Rstrings < Rbkb::Cli::Executable
|
8
|
+
def initialize(*args)
|
9
|
+
super(*args) do |this|
|
10
|
+
{
|
11
|
+
:start_off => 0,
|
12
|
+
:end_off => -1,
|
13
|
+
:encoding => :both,
|
14
|
+
:minimum => 6,
|
15
|
+
:align => nil,
|
16
|
+
:indat => Array.new,
|
17
|
+
:fnames => Array.new,
|
18
|
+
}.each {|k,v| this.opts[k] ||= v }
|
19
|
+
|
20
|
+
yield this if block_given?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def make_parser()
|
25
|
+
arg = super()
|
26
|
+
arg.banner += " <file ... || blank for stdin>"
|
27
|
+
|
28
|
+
arg.on("-s", "--start=OFFSET", "Start at offset") do |s|
|
29
|
+
unless m=/^(?:(\d+)|0x([A-Fa-f0-9]+))$/.match(s)
|
30
|
+
bail "invalid offset '#{s}'"
|
31
|
+
end
|
32
|
+
@opts[:start_off] = (m[2])? m[0].hex : m[0].to_i
|
33
|
+
end
|
34
|
+
|
35
|
+
arg.on("-e", "--end=OFFSET", "End at offset") do |e|
|
36
|
+
unless m=/^(?:(\d+)|0x([A-Fa-f0-9]+))$/.match(e)
|
37
|
+
bail "invalid offset '#{e}'"
|
38
|
+
end
|
39
|
+
@opts[:end_off] = (m[2])? m[0].hex : m[0].to_i
|
40
|
+
end
|
41
|
+
|
42
|
+
arg.on("-t", "--encoding-type=TYPE",
|
43
|
+
"Encoding: ascii/unicode/both (default=#{@opts[:encoding]})") do |t|
|
44
|
+
@opts[:encoding] = t.to_sym
|
45
|
+
end
|
46
|
+
|
47
|
+
arg.on("-l", "--min-length=NUM", Numeric,
|
48
|
+
"Minimum length of strings (default=#{@opts[:minimum]})") do |l|
|
49
|
+
@opts[:minimum] = l
|
50
|
+
end
|
51
|
+
|
52
|
+
arg.on("-a", "--align=ALIGNMENT", Numeric,
|
53
|
+
"Match only on alignment (default=none)") do |a|
|
54
|
+
(@opts[:align] = a) > 0 or bail "bad alignment '#{a}'"
|
55
|
+
end
|
56
|
+
|
57
|
+
return arg
|
58
|
+
end
|
59
|
+
|
60
|
+
def parse(*args)
|
61
|
+
super(*args)
|
62
|
+
if @opts[:indat].empty? and not @argv.empty?
|
63
|
+
while a=@argv.shift
|
64
|
+
@opts[:indat] << do_file_read(a)
|
65
|
+
@opts[:fnames] << a
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
parse_catchall()
|
70
|
+
|
71
|
+
if @opts[:indat].empty?
|
72
|
+
@opts[:indat] << @stdin.read() if @opts[:indat].empty?
|
73
|
+
@opts[:fnames] << "[STDIN]"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def go(*args)
|
78
|
+
super(*args)
|
79
|
+
|
80
|
+
start_off = @opts[:start_off]
|
81
|
+
end_off = @opts[:end_off]
|
82
|
+
enc = @opts[:encoding]
|
83
|
+
min = @opts[:minimum]
|
84
|
+
align = @opts[:align]
|
85
|
+
|
86
|
+
@opts[:pr_fnames]=true if @opts[:fnames].size > 1
|
87
|
+
|
88
|
+
i=0
|
89
|
+
while buf=@opts[:indat].shift
|
90
|
+
buf[start_off..end_off].strings(
|
91
|
+
:encoding => enc,
|
92
|
+
:minimum => min,
|
93
|
+
:align => align
|
94
|
+
) do |off, len, type, str|
|
95
|
+
if @opts[:pr_fnames]
|
96
|
+
@stdout << "#{@opts[:fnames][i]}:"
|
97
|
+
end
|
98
|
+
@stdout << "#{(off+start_off).to_hex.rjust(8,"0")}:"+
|
99
|
+
"#{(len+start_off).to_hex.rjust(8,"0")}:"+
|
100
|
+
"#{type.to_s[0,1]}:#{str.delete("\000").inspect}\n"
|
101
|
+
end
|
102
|
+
i+=1
|
103
|
+
end
|
104
|
+
|
105
|
+
self.exit(0)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rbkb/cli'
|
2
|
+
|
3
|
+
# Copyright 2009 emonti at matasano.com
|
4
|
+
# See README.rdoc for license information
|
5
|
+
#
|
6
|
+
# Returns a slice from input. This is just a shell interface to a String.slice
|
7
|
+
# operation.
|
8
|
+
class Rbkb::Cli::Slice < Rbkb::Cli::Executable
|
9
|
+
|
10
|
+
def initialize(*args)
|
11
|
+
super(*args)
|
12
|
+
@opts[:last] ||= -1
|
13
|
+
end
|
14
|
+
|
15
|
+
def make_parser()
|
16
|
+
super()
|
17
|
+
add_std_file_opt(:indat)
|
18
|
+
add_range_opts(:first, :last)
|
19
|
+
arg = @oparse
|
20
|
+
|
21
|
+
arg.banner += " start (no args when using -r or -x)"
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def parse(*args)
|
26
|
+
super(*args)
|
27
|
+
@opts[:first] ||= @argv.shift
|
28
|
+
|
29
|
+
unless(Numeric === @opts[:first] or /^-?\d+$/.match(@opts[:first]) )
|
30
|
+
bail_args "invalid start length"
|
31
|
+
end
|
32
|
+
|
33
|
+
parse_catchall()
|
34
|
+
|
35
|
+
@opts[:first] = @opts[:first].to_i
|
36
|
+
@opts[:indat] ||= @stdin.read()
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def go(*args)
|
41
|
+
super(*args)
|
42
|
+
@stdout << @opts[:indat][ @opts[:first] .. @opts[:last] ]
|
43
|
+
self.exit(0)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'rbkb/plug/cli'
|
2
|
+
|
3
|
+
# Copyright 2009 emonti at matasano.com
|
4
|
+
# See README.rdoc for license information
|
5
|
+
#
|
6
|
+
# This is an implementation of the original blackbag "telson" around
|
7
|
+
# ruby and eventmachine.
|
8
|
+
#
|
9
|
+
# Telson can do the following things with minimum fuss:
|
10
|
+
# - Run as a "stubbed" network client using UDP or TCP
|
11
|
+
# - Debugging network protocols
|
12
|
+
# - Observe client/server behaviors using different messages at
|
13
|
+
# various phases of a conversation.
|
14
|
+
#
|
15
|
+
class Rbkb::Cli::Telson < Rbkb::Cli::PlugCli
|
16
|
+
|
17
|
+
def initialize(*args)
|
18
|
+
super(*args) do |this|
|
19
|
+
this.local_addr = "0.0.0.0"
|
20
|
+
this.local_port = 0
|
21
|
+
end
|
22
|
+
|
23
|
+
@persist = false
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def make_parser()
|
28
|
+
arg = super()
|
29
|
+
|
30
|
+
arg.on("-r", "--reconnect", "Attempt to reconnect endlessly.") do
|
31
|
+
@persist=true
|
32
|
+
end
|
33
|
+
|
34
|
+
arg.on("-s", "--source=(ADDR:?)PORT", "Bind client on port and addr") do |p|
|
35
|
+
if m=/^(?:([\w\.]+):)?(\d+)$/.match(p)
|
36
|
+
@local_addr = $1 if $1
|
37
|
+
@local_port = $2.to_i
|
38
|
+
else
|
39
|
+
bail("Invalid source argument: #{p.inspect}")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def parse(*args)
|
46
|
+
super(*args)
|
47
|
+
|
48
|
+
parse_target_argument()
|
49
|
+
parse_catchall()
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def go(*args)
|
54
|
+
super(*args)
|
55
|
+
loop do
|
56
|
+
EventMachine.run {
|
57
|
+
if @transport == :TCP
|
58
|
+
|
59
|
+
c=EventMachine.bind_connect( @local_addr,
|
60
|
+
@local_port,
|
61
|
+
@target_addr,
|
62
|
+
@target_port,
|
63
|
+
Plug::Telson,
|
64
|
+
@transport,
|
65
|
+
@plug_opts )
|
66
|
+
elsif @transport == :UDP
|
67
|
+
c=EventMachine.open_datagram_socket( @local_addr,
|
68
|
+
@local_port,
|
69
|
+
Plug::Telson,
|
70
|
+
@transport,
|
71
|
+
@plug_opts )
|
72
|
+
|
73
|
+
c.peers.add_peer_manually(@target_addr, @target_port)
|
74
|
+
|
75
|
+
### someday maybe raw or others?
|
76
|
+
else
|
77
|
+
raise "bad transport protocol"
|
78
|
+
end
|
79
|
+
EventMachine.start_server(@blit_addr, @blit_port, Plug::Blit, @blit_proto, c)
|
80
|
+
Plug::UI::verbose("** BLITSRV-#{@blit_addr}:#{@blit_port}(TCP) Started") # XXX
|
81
|
+
}
|
82
|
+
break unless @persist
|
83
|
+
Plug::UI::verbose("** RECONNECTING") # XXX
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rbkb/cli'
|
2
|
+
|
3
|
+
# Copyright 2009 emonti at matasano.com
|
4
|
+
# See README.rdoc for license information
|
5
|
+
#
|
6
|
+
# unhexify converts a string of hex bytes back to raw data. Input can be
|
7
|
+
# supplied via stdin, a hex-string argument, or a file containing hex (use -f).
|
8
|
+
class Rbkb::Cli::Unhexify < Rbkb::Cli::Executable
|
9
|
+
def make_parser
|
10
|
+
super()
|
11
|
+
add_std_file_opt(:indat)
|
12
|
+
arg = @oparse
|
13
|
+
|
14
|
+
#----------------------------------------------------------------------
|
15
|
+
# Add local options
|
16
|
+
arg.banner += " <data | blank for stdin>"
|
17
|
+
|
18
|
+
arg.on("-d", "--delim DELIMITER",
|
19
|
+
"DELIMITER regex between hex chunks") do |d|
|
20
|
+
@opts[:delim] = Regexp.new(d.gsub('\\\\', '\\'))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def parse(*args)
|
25
|
+
super(*args)
|
26
|
+
|
27
|
+
# default string arg
|
28
|
+
if @opts[:indat].nil? and a=@argv.shift
|
29
|
+
@opts[:indat] = a.dup
|
30
|
+
end
|
31
|
+
|
32
|
+
# catchall
|
33
|
+
bail_args @argv.join(' ') if ARGV.length != 0
|
34
|
+
end
|
35
|
+
|
36
|
+
def go(*args)
|
37
|
+
super(*args)
|
38
|
+
|
39
|
+
# Default to standard input
|
40
|
+
@opts[:indat] ||= @stdin.read()
|
41
|
+
|
42
|
+
@opts[:indat].delete!("\r\n")
|
43
|
+
@opts[:delim] ||= Regexp.new('\s*')
|
44
|
+
|
45
|
+
@stdout << @opts[:indat].unhexify(@opts[:delim])
|
46
|
+
|
47
|
+
self.exit(0)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'rbkb/cli'
|
2
|
+
|
3
|
+
# Copyright 2009 emonti at matasano.com
|
4
|
+
# See README.rdoc for license information
|
5
|
+
#
|
6
|
+
# urldec converts a url percent-encoded string back to its raw form.
|
7
|
+
# Input can be supplied via stdin, a string argument, or a file (with -f).
|
8
|
+
# (url percent-encoding is just fancy hex encoding)
|
9
|
+
class Rbkb::Cli::Urldec < Rbkb::Cli::Executable
|
10
|
+
def make_parser()
|
11
|
+
super()
|
12
|
+
add_std_file_opt(:indat)
|
13
|
+
arg = @oparse
|
14
|
+
arg.banner += " <data | blank for stdin>"
|
15
|
+
|
16
|
+
arg.on("-p", "--[no-]plus", "Convert '+' to space (default: true)") do |p|
|
17
|
+
@opts[:noplus] = (not p)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def parse(*args)
|
22
|
+
super(*args)
|
23
|
+
parse_string_argument(:indat)
|
24
|
+
parse_catchall()
|
25
|
+
end
|
26
|
+
|
27
|
+
def go(*args)
|
28
|
+
super(*args)
|
29
|
+
# Default to standard input
|
30
|
+
@opts[:indat] ||= @stdin.read()
|
31
|
+
@stdout << @opts[:indat].urldec(:noplus => @opts[:noplus])
|
32
|
+
self.exit(0)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|