emonti-rbkb 0.6.1.3 → 0.6.2
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/README.rdoc +191 -24
- data/bin/b64 +2 -54
- data/bin/bgrep +2 -88
- data/bin/blit +2 -94
- data/bin/c +2 -11
- data/bin/crc32 +2 -57
- data/bin/d64 +2 -38
- data/bin/dedump +2 -50
- data/bin/hexify +2 -82
- data/bin/len +2 -71
- data/bin/plugsrv +56 -61
- data/bin/rstrings +2 -120
- data/bin/slice +2 -71
- data/bin/telson +2 -106
- data/bin/unhexify +2 -62
- data/bin/urldec +2 -53
- data/bin/urlenc +2 -52
- data/bin/xor +2 -57
- data/lib/rbkb/cli/b64.rb +27 -0
- data/lib/rbkb/cli/bgrep.rb +78 -0
- data/lib/rbkb/cli/blit.rb +86 -0
- data/lib/rbkb/cli/chars.rb +20 -0
- data/lib/rbkb/cli/crc32.rb +29 -0
- data/lib/rbkb/cli/d64.rb +22 -0
- data/lib/rbkb/cli/dedump.rb +47 -0
- data/lib/rbkb/cli/hexify.rb +64 -0
- data/lib/rbkb/cli/len.rb +70 -0
- data/lib/rbkb/cli/rstrings.rb +102 -0
- data/lib/rbkb/cli/slice.rb +43 -0
- data/lib/rbkb/cli/telson.rb +116 -0
- data/lib/rbkb/cli/unhexify.rb +53 -0
- data/lib/rbkb/cli/urldec.rb +31 -0
- data/lib/rbkb/cli/urlenc.rb +31 -0
- data/lib/rbkb/cli/xor.rb +40 -0
- data/lib/rbkb/cli.rb +212 -0
- data/lib/rbkb/extends.rb +16 -14
- data/lib/rbkb/plug/blit.rb +5 -5
- data/lib/rbkb/plug/proxy.rb +23 -0
- data/lib/rbkb.rb +2 -2
- metadata +22 -5
- data/lib/rbkb/command_line.rb +0 -41
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'rbkb/cli'
|
2
|
+
|
3
|
+
# rstrings is Unix "strings" in ruby... with some extra stuff
|
4
|
+
class Rbkb::Cli::Rstrings < Rbkb::Cli::Executable
|
5
|
+
def initialize(*args)
|
6
|
+
super(*args)
|
7
|
+
{
|
8
|
+
:start_off => 0,
|
9
|
+
:end_off => -1,
|
10
|
+
:encoding => :both,
|
11
|
+
:minimum => 6,
|
12
|
+
:align => nil,
|
13
|
+
:indat => Array.new,
|
14
|
+
:fnames => Array.new,
|
15
|
+
}.each {|k,v| @opts[k] ||= v }
|
16
|
+
end
|
17
|
+
|
18
|
+
def make_parser()
|
19
|
+
arg = super()
|
20
|
+
arg.banner += " <file ... || blank for stdin>"
|
21
|
+
|
22
|
+
arg.on("-s", "--start=OFFSET", "Start at offset") do |s|
|
23
|
+
unless m=/^(?:(\d+)|0x([A-Fa-f0-9]+))$/.match(s)
|
24
|
+
bail "invalid offset '#{s}'"
|
25
|
+
end
|
26
|
+
@opts[:start_off] = (m[2])? m[0].hex : m[0].to_i
|
27
|
+
end
|
28
|
+
|
29
|
+
arg.on("-e", "--end=OFFSET", "End at offset") do |e|
|
30
|
+
unless m=/^(?:(\d+)|0x([A-Fa-f0-9]+))$/.match(e)
|
31
|
+
bail "invalid offset '#{e}'"
|
32
|
+
end
|
33
|
+
@opts[:end_off] = (m[2])? m[0].hex : m[0].to_i
|
34
|
+
end
|
35
|
+
|
36
|
+
arg.on("-t", "--encoding-type=TYPE",
|
37
|
+
"Encoding: ascii/unicode/both (default=#{@opts[:encoding]})") do |t|
|
38
|
+
@opts[:encoding] = t.to_sym
|
39
|
+
end
|
40
|
+
|
41
|
+
arg.on("-l", "--min-length=NUM", Numeric,
|
42
|
+
"Minimum length of strings (default=#{@opts[:minimum]})") do |l|
|
43
|
+
@opts[:minimum] = l
|
44
|
+
end
|
45
|
+
|
46
|
+
arg.on("-a", "--align=ALIGNMENT", Numeric,
|
47
|
+
"Match only on alignment (default=none)") do |a|
|
48
|
+
(@opts[:align] = a) > 0 or bail "bad alignment '#{a}'"
|
49
|
+
end
|
50
|
+
|
51
|
+
return arg
|
52
|
+
end
|
53
|
+
|
54
|
+
def parse(*args)
|
55
|
+
super(*args)
|
56
|
+
if @opts[:indat].empty? and not @argv.empty?
|
57
|
+
while a=@argv.shift
|
58
|
+
@opts[:indat] << do_file_read(a)
|
59
|
+
@opts[:fnames] << a
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
parse_catchall()
|
64
|
+
|
65
|
+
if @opts[:indat].empty?
|
66
|
+
@opts[:indat] << @stdin.read() if @opts[:indat].empty?
|
67
|
+
@opts[:fnames] << "[STDIN]"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def go(*args)
|
72
|
+
super(*args)
|
73
|
+
|
74
|
+
start_off = @opts[:start_off]
|
75
|
+
end_off = @opts[:end_off]
|
76
|
+
enc = @opts[:encoding]
|
77
|
+
min = @opts[:minimum]
|
78
|
+
align = @opts[:align]
|
79
|
+
|
80
|
+
@opts[:pr_fnames]=true if @opts[:fnames].size > 1
|
81
|
+
|
82
|
+
i=0
|
83
|
+
while buf=@opts[:indat].shift
|
84
|
+
buf[start_off..end_off].strings(
|
85
|
+
:encoding => enc,
|
86
|
+
:minimum => min,
|
87
|
+
:align => align
|
88
|
+
) do |off, len, type, str|
|
89
|
+
if @opts[:pr_fnames]
|
90
|
+
@stdout << "#{@opts[:fnames][i]}:"
|
91
|
+
end
|
92
|
+
@stdout << "#{(off+start_off).to_hex.rjust(8,"0")}:"+
|
93
|
+
"#{(len+start_off).to_hex.rjust(8,"0")}:"+
|
94
|
+
"#{type.to_s[0,1]}:#{str.delete("\000").inspect}\n"
|
95
|
+
end
|
96
|
+
i+=1
|
97
|
+
end
|
98
|
+
|
99
|
+
self.exit(0)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rbkb/cli'
|
2
|
+
|
3
|
+
# Returns a slice from input. This is just a shell interface to a String.slice
|
4
|
+
# operation.
|
5
|
+
class Rbkb::Cli::Slice < Rbkb::Cli::Executable
|
6
|
+
|
7
|
+
def initialize(*args)
|
8
|
+
super(*args)
|
9
|
+
@opts[:last] ||= -1
|
10
|
+
end
|
11
|
+
|
12
|
+
def make_parser()
|
13
|
+
super()
|
14
|
+
add_std_file_opt(:indat)
|
15
|
+
add_range_opts(:first, :last)
|
16
|
+
arg = @oparse
|
17
|
+
|
18
|
+
arg.banner += " start (no args when using -r or -x)"
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def parse(*args)
|
23
|
+
super(*args)
|
24
|
+
@opts[:first] ||= @argv.shift
|
25
|
+
|
26
|
+
unless(Numeric === @opts[:first] or /^-?\d+$/.match(@opts[:first]) )
|
27
|
+
bail_args "invalid start length"
|
28
|
+
end
|
29
|
+
|
30
|
+
parse_catchall()
|
31
|
+
|
32
|
+
@opts[:first] = @opts[:first].to_i
|
33
|
+
@opts[:indat] ||= @stdin.read()
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def go(*args)
|
38
|
+
super(*args)
|
39
|
+
@stdout << @opts[:indat][ @opts[:first] .. @opts[:last] ]
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'rbkb/cli'
|
2
|
+
require 'rbkb/plug'
|
3
|
+
require 'eventmachine'
|
4
|
+
|
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 server or 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::Executable
|
16
|
+
|
17
|
+
def initialize(*args)
|
18
|
+
super(*args)
|
19
|
+
@b_addr = Plug::Blit::DEFAULT_IPADDR
|
20
|
+
@b_port = Plug::Blit::DEFAULT_PORT
|
21
|
+
@srced = @persist = false
|
22
|
+
@s_addr = "0.0.0.0"
|
23
|
+
@s_port = 0
|
24
|
+
@proto = :TCP
|
25
|
+
|
26
|
+
# XXX TODO Plug::UI obviously need fixing. It shouldn't be a module
|
27
|
+
# with constants for configuration
|
28
|
+
Plug::UI::LOGCFG[:verbose] = true
|
29
|
+
Plug::UI::LOGCFG[:dump] = :hex
|
30
|
+
Plug::UI::LOGCFG[:out] = @stderr
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def make_parser()
|
35
|
+
arg = super()
|
36
|
+
arg.banner += " host:port"
|
37
|
+
|
38
|
+
arg.on("-u", "--udp", "UDP mode") do
|
39
|
+
@proto=:UDP
|
40
|
+
end
|
41
|
+
|
42
|
+
arg.on("-b", "--blit=ADDR:PORT", "Where to listen for blit") do |b|
|
43
|
+
unless m=/^(?:([\w\.]+):)?(\d+)$/.match(b)
|
44
|
+
bail("Invalid blit address/port")
|
45
|
+
end
|
46
|
+
@b_port = m[2].to_i
|
47
|
+
@b_addr = m[1] if m[1]
|
48
|
+
end
|
49
|
+
|
50
|
+
arg.on("-o", "--output=FILE", "Output to file instead of screen") do |f|
|
51
|
+
Plug::UI::LOGCFG[:out] = File.open(f, "w") # XXX
|
52
|
+
end
|
53
|
+
|
54
|
+
arg.on("-q", "--quiet", "Turn off verbose logging") do
|
55
|
+
Plug::UI::LOGCFG[:verbose] = false # XXX
|
56
|
+
end
|
57
|
+
|
58
|
+
arg.on("-r", "--reconnect", "Attempt to reconnect endlessly.") do
|
59
|
+
@persist=true
|
60
|
+
end
|
61
|
+
|
62
|
+
arg.on("-s", "--source=(ADDR:?)PORT", "Bind on port (and addr?)") do |p|
|
63
|
+
if m=/^(?:([\w\.]+):)?(\d+)$/.match(p)
|
64
|
+
@s_addr = $1 if $1
|
65
|
+
@s_port = $2.to_i
|
66
|
+
@srced = true
|
67
|
+
else
|
68
|
+
bail("Invalid listen argument: #{p.inspect}")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
def parse(*args)
|
75
|
+
super(*args)
|
76
|
+
|
77
|
+
# Get target argument
|
78
|
+
unless (m = /^([\w\.]+):(\d+)$/.match(@argv.shift)) and @argv.shift.nil?
|
79
|
+
bail "Invalid target #{arg}"
|
80
|
+
end
|
81
|
+
|
82
|
+
@t_addr = m[1]
|
83
|
+
@t_port = m[2].to_i
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
def go(*args)
|
88
|
+
super(*args)
|
89
|
+
|
90
|
+
loop do
|
91
|
+
EventMachine.run {
|
92
|
+
if @proto == :TCP
|
93
|
+
bail("Sorry: --source only works with UDP.") if @srced
|
94
|
+
|
95
|
+
c=EventMachine.connect(@t_addr, @t_port, Plug::Telson, @proto)
|
96
|
+
|
97
|
+
elsif @proto == :UDP
|
98
|
+
c=EventMachine.open_datagram_socket(
|
99
|
+
@s_addr, @s_port, Plug::Telson, @proto
|
100
|
+
)
|
101
|
+
c.peers.add_peer_manually(@t_addr, @t_port)
|
102
|
+
|
103
|
+
### someday maybe raw or others?
|
104
|
+
else
|
105
|
+
raise "bad protocol"
|
106
|
+
end
|
107
|
+
|
108
|
+
EventMachine.start_server(@b_addr, @b_port, Plug::Blit, :TCP, c)
|
109
|
+
Plug::UI::verbose("** BLITSRV-#{@b_addr}:#{@b_port}(TCP) Started") # XXX
|
110
|
+
}
|
111
|
+
break unless @persist
|
112
|
+
Plug::UI::verbose("** RECONNECTING") # XXX
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rbkb/cli'
|
4
|
+
|
5
|
+
# unhexify converts a string of hex bytes back to raw data. Input can be
|
6
|
+
# supplied via stdin, a hex-string argument, or a file containing hex (use -f).
|
7
|
+
class Rbkb::Cli::Unhexify < Rbkb::Cli::Executable
|
8
|
+
def make_parser
|
9
|
+
super()
|
10
|
+
add_std_file_opt(:indat)
|
11
|
+
arg = @oparse
|
12
|
+
|
13
|
+
#----------------------------------------------------------------------
|
14
|
+
# Add local options
|
15
|
+
arg.banner += " <data | blank for stdin>"
|
16
|
+
|
17
|
+
arg.on("-d", "--delim DELIMITER",
|
18
|
+
"DELIMITER regex between hex chunks") do |d|
|
19
|
+
@opts[:delim] = Regexp.new(d.gsub('\\\\', '\\'))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse(*args)
|
24
|
+
super(*args)
|
25
|
+
|
26
|
+
# default string arg
|
27
|
+
if @opts[:indat].nil? and a=@argv.shift
|
28
|
+
@opts[:indat] = a.dup
|
29
|
+
end
|
30
|
+
|
31
|
+
# catchall
|
32
|
+
bail_args @argv.join(' ') if ARGV.length != 0
|
33
|
+
end
|
34
|
+
|
35
|
+
def go(*args)
|
36
|
+
super(*args)
|
37
|
+
|
38
|
+
# Default to standard input
|
39
|
+
@opts[:indat] ||= @stdin.read()
|
40
|
+
|
41
|
+
@opts[:indat].delete!("\r\n")
|
42
|
+
@opts[:delim] ||= /\s*/
|
43
|
+
|
44
|
+
unless out = @opts[:indat].unhexify(@opts[:delim])
|
45
|
+
bail "Error: Failed parsing as hex"
|
46
|
+
end
|
47
|
+
|
48
|
+
@stdout << out
|
49
|
+
|
50
|
+
self.exit(0)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rbkb/cli'
|
2
|
+
|
3
|
+
# urldec converts a url percent-encoded string back to its raw form.
|
4
|
+
# Input can be supplied via stdin, a string argument, or a file (with -f).
|
5
|
+
# (url percent-encoding is just fancy hex encoding)
|
6
|
+
class Rbkb::Cli::Urldec < Rbkb::Cli::Executable
|
7
|
+
def make_parser()
|
8
|
+
super()
|
9
|
+
add_std_file_opt(:indat)
|
10
|
+
arg = @oparse
|
11
|
+
arg.banner += " <data | blank for stdin>"
|
12
|
+
|
13
|
+
arg.on("-p", "--[no-]plus", "Convert '+' to space (default: true)") do |p|
|
14
|
+
@opts[:noplus] = (not p)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def parse(*args)
|
19
|
+
super(*args)
|
20
|
+
parse_string_argument(:indat)
|
21
|
+
parse_catchall()
|
22
|
+
end
|
23
|
+
|
24
|
+
def go(*args)
|
25
|
+
super(*args)
|
26
|
+
# Default to standard input
|
27
|
+
@opts[:indat] ||= @stdin.read()
|
28
|
+
@stdout << @opts[:indat].urldec(:noplus => @opts[:noplus])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rbkb/cli'
|
2
|
+
|
3
|
+
# urlenc converts a string or raw data to a url percent-encoded string
|
4
|
+
# Input can be supplied via stdin, a string argument, or a file (with -f).
|
5
|
+
# (url percent-encoding is just fancy hex encoding)
|
6
|
+
class Rbkb::Cli::Urlenc < Rbkb::Cli::Executable
|
7
|
+
def make_parser()
|
8
|
+
super()
|
9
|
+
add_std_file_opt(:indat)
|
10
|
+
arg = @oparse
|
11
|
+
arg.banner += " <data | blank for stdin>"
|
12
|
+
|
13
|
+
arg.on("-p", "--[no-]plus",
|
14
|
+
"Convert spaces to '+' (default: false)") do |p|
|
15
|
+
@opts[:plus] = p
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse(*args)
|
20
|
+
super(*args)
|
21
|
+
parse_string_argument(:indat)
|
22
|
+
parse_catchall()
|
23
|
+
end
|
24
|
+
|
25
|
+
def go(*args)
|
26
|
+
super(*args)
|
27
|
+
# Default to standard input
|
28
|
+
@opts[:indat] ||= @stdin.read()
|
29
|
+
@stdout << @opts[:indat].urlenc(:plus => @opts[:plus]) + "\n"
|
30
|
+
end
|
31
|
+
end
|
data/lib/rbkb/cli/xor.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rbkb/cli'
|
3
|
+
|
4
|
+
# Repeating string xor. Takes input from a string, stdin, or a file (-f).
|
5
|
+
class Rbkb::Cli::Xor < Rbkb::Cli::Executable
|
6
|
+
def make_parser()
|
7
|
+
super()
|
8
|
+
add_std_file_opt(:indat)
|
9
|
+
arg = @oparse
|
10
|
+
arg.banner += " -k|-s <key> <data | stdin>"
|
11
|
+
|
12
|
+
arg.separator " Key options (you must specify one of the following):"
|
13
|
+
arg.on("-s", "--strkey STRING", "xor against STRING") do |s|
|
14
|
+
bail "only one key option can be specified with -s or -x" if @opts[:key]
|
15
|
+
@opts[:key] = s
|
16
|
+
end
|
17
|
+
|
18
|
+
arg.on("-x", "--hexkey HEXSTR", "xor against binary HEXSTR") do |x|
|
19
|
+
bail "only one key option can be specified with -s or -x" if @opts[:key]
|
20
|
+
x.sub!(/^0[xX]/, '')
|
21
|
+
bail "Unable to parse hex string" unless @opts[:key] = x.unhexify
|
22
|
+
end
|
23
|
+
return arg
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse(*args)
|
27
|
+
super(*args)
|
28
|
+
bail("You must specify a key with -s or -x\n#{@oparse}") unless @opts[:key]
|
29
|
+
parse_string_argument(:indat)
|
30
|
+
parse_catchall()
|
31
|
+
end
|
32
|
+
|
33
|
+
def go(*args)
|
34
|
+
super(*args)
|
35
|
+
@opts[:indat] ||= @stdin.read
|
36
|
+
@stdout << @opts[:indat].xor(@opts[:key])
|
37
|
+
self.exit(0)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
data/lib/rbkb/cli.rb
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
require 'rbkb'
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
module Rbkb::Cli
|
5
|
+
# Rbkb::Cli::Executable is an abstract class for creating command line
|
6
|
+
# executables using the Ruby Black Bag framework.
|
7
|
+
class Executable
|
8
|
+
|
9
|
+
def self.run(param={})
|
10
|
+
new(param).go
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_accessor :stdout, :stderr, :stdin, :argv, :opts, :oparse
|
14
|
+
|
15
|
+
# Instantiates a new Executable object.
|
16
|
+
#
|
17
|
+
# The 'param' argument is a named value hash. The following keys are
|
18
|
+
# significant:
|
19
|
+
#
|
20
|
+
# :argv - An array of cli arguments (default ARGV)
|
21
|
+
# :opts - executable/function options for use when running 'go'
|
22
|
+
# :stdout, - IO redirection (mostly for unit tests)
|
23
|
+
# :stderr,
|
24
|
+
# :stdin
|
25
|
+
#
|
26
|
+
#
|
27
|
+
# The above keys are deleted from the 'param' hash and stored as instance
|
28
|
+
# variables with attr_accessors. All other parameters are ignored.
|
29
|
+
def initialize(param={})
|
30
|
+
@argv ||= param.delete(:argv) || ARGV
|
31
|
+
@stdout ||= param.delete(:stdout) || STDOUT
|
32
|
+
@stderr ||= param.delete(:stderr) || STDERR
|
33
|
+
@stdin ||= param.delete(:stdin) || STDIN
|
34
|
+
@opts ||= param.delete(:opts) || {}
|
35
|
+
make_parser()
|
36
|
+
yield self if block_given?
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# Wrapper for Kernel.exit() so we can unit test cli tools
|
41
|
+
def exit(ret)
|
42
|
+
if defined? Rbkb::Cli::TESTING
|
43
|
+
raise("Exited with return code: #{ret}") if ret != 0
|
44
|
+
else
|
45
|
+
Kernel.exit(ret)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
# This method exits with a message on stderr
|
51
|
+
def bail(msg)
|
52
|
+
@stderr.puts msg if msg
|
53
|
+
self.exit(1)
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
# This method wraps a 'bail' with a basic argument error mesage and hint
|
58
|
+
# for the '-h or --help' flag
|
59
|
+
# The 'arg_err' parameter is a string with the erroneous arguments
|
60
|
+
def bail_args(arg_err)
|
61
|
+
bail "Error: bad arguments - #{arg_err}\n Hint: Use -h or --help"
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
# Prepares an OptionsParser object with blackbag standard options
|
66
|
+
# This is called from within initialize() and should be overridden in
|
67
|
+
# inherited classes to add additional OptionParser-based parsers.
|
68
|
+
#
|
69
|
+
# See parse for actual parsing.
|
70
|
+
def make_parser
|
71
|
+
@oparse ||= OptionParser.new
|
72
|
+
@oparse.banner = "Usage: #{File.basename $0} [options]"
|
73
|
+
|
74
|
+
@oparse.on("-h", "--help", "Show this message") do
|
75
|
+
bail(@oparse)
|
76
|
+
end
|
77
|
+
|
78
|
+
@oparse.on("-v", "--version", "Show version and exit") do
|
79
|
+
bail("Ruby BlackBag version #{Rbkb::VERSION}")
|
80
|
+
end
|
81
|
+
|
82
|
+
return @oparse
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
# Abstract argument parser. Override this method with super() from
|
87
|
+
# inherited executables. The base method just calls OptionParser.parse!
|
88
|
+
# on the internal @oparse object.
|
89
|
+
def parse
|
90
|
+
# parse flag arguments
|
91
|
+
@oparse.parse!(@argv) rescue(bail_args($!))
|
92
|
+
@parsed=true
|
93
|
+
|
94
|
+
# the overriding class may implement additional arguments from here
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
# Abstract 'runner'. Override this method with super() from inherited
|
99
|
+
# executables. The base method just slurps in an optional argv and
|
100
|
+
# runs 'parse' if it hasn't already
|
101
|
+
def go(argv=nil)
|
102
|
+
if argv
|
103
|
+
@argv = argv
|
104
|
+
end
|
105
|
+
|
106
|
+
parse
|
107
|
+
|
108
|
+
# the overriding class implements actual functionality beyond here
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
# Wraps a file read with a standard bail error message
|
115
|
+
def do_file_read(f)
|
116
|
+
File.read(f) rescue(bail "File Read Error: #{$!}")
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
# Implements a basic input file argument. File reading is handled
|
121
|
+
# by do_file_read().
|
122
|
+
#
|
123
|
+
# Takes one argument, which is the @opts hash keyname to store
|
124
|
+
# the file data into.
|
125
|
+
# (Used commonly throughout several executables)
|
126
|
+
def add_std_file_opt(inkey)
|
127
|
+
@oparse.on("-f", "--file FILENAME", "Input from FILENAME") do |f|
|
128
|
+
@opts[inkey] = do_file_read(f)
|
129
|
+
end
|
130
|
+
return @oparse
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
# Implements numeric and hex range options via '-r' and '-x'
|
135
|
+
#
|
136
|
+
# Takes two arguments which are the @opts hash key names for
|
137
|
+
# first and last parameters.
|
138
|
+
#
|
139
|
+
# (Used commonly throughout several executables)
|
140
|
+
def add_range_opts(fkey, lkey)
|
141
|
+
@oparse.on("-r", "--range=START[:END]",
|
142
|
+
"Start and optional end range") do |r|
|
143
|
+
|
144
|
+
raise "-x and -r are mutually exclusive" if @parser_got_range
|
145
|
+
@parser_got_range=true
|
146
|
+
|
147
|
+
unless m=/^(-?[0-9]+)(?::(-?[0-9]+))?$/.match(r)
|
148
|
+
raise "invalid range #{r.inspect}"
|
149
|
+
end
|
150
|
+
|
151
|
+
@opts[fkey] = $1.to_i
|
152
|
+
@opts[lkey] = $2.to_i if $2
|
153
|
+
end
|
154
|
+
|
155
|
+
@oparse.on("-x", "--hexrange=START[:END]",
|
156
|
+
"Start and optional end range in hex") do |r|
|
157
|
+
|
158
|
+
raise "-x and -r are mutually exclusive" if @parser_got_range
|
159
|
+
@parser_got_range=true
|
160
|
+
|
161
|
+
unless m=/^(-?[0-9a-f]+)(?::(-?[0-9a-f]+))?$/i.match(r)
|
162
|
+
raise "invalid range #{r.inspect}"
|
163
|
+
end
|
164
|
+
|
165
|
+
@opts[fkey] =
|
166
|
+
if ($1[0,1] == '-')
|
167
|
+
($1[1..-1]).hex_to_num * -1
|
168
|
+
else
|
169
|
+
$1.hex_to_num
|
170
|
+
end
|
171
|
+
|
172
|
+
if $2
|
173
|
+
@opts[lkey] =
|
174
|
+
if($2[0,1] == '-')
|
175
|
+
$2[1..-1].hex_to_num * -1
|
176
|
+
else
|
177
|
+
$2.hex_to_num
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
# Conditionally parses a string argument. Uses 'key' to first check for
|
185
|
+
# then store it in @opts hash if it is not yet there.
|
186
|
+
# (Used commonly throughout several executables)
|
187
|
+
def parse_string_argument(key)
|
188
|
+
if @opts[key].nil? and s=@argv.shift
|
189
|
+
@opts[key] = s.dup
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
|
194
|
+
# Conditionally parses a file argument. Uses 'key' to first check for
|
195
|
+
# then store it in @opts hash if it is not yet there.
|
196
|
+
# (Used commonly throughout several executables)
|
197
|
+
def parse_file_argument(key)
|
198
|
+
if @opts[key].nil? and f=@argv.shift
|
199
|
+
@opts[key] = do_file_read(f)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# For use at the end of a parser - calls bail_args with remaining
|
204
|
+
# arguments if there are extra arguments.
|
205
|
+
# (Used commonly throughout several executables)
|
206
|
+
def parse_catchall
|
207
|
+
bail_args(@argv.join(' ')) if(@argv.length != 0)
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|