emonti-rbkb 0.6.1.3 → 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|