From ed3b1cecd47d95d39b2ce0071167cee63ae656a4 Mon Sep 17 00:00:00 2001 From: RageLtMan Date: Thu, 28 Mar 2013 04:02:31 -0400 Subject: [PATCH 1/6] Rex::Text::Ui::Table.new[find_by_colnames] Add :[] to ...Ui::Table allowing user to pass multiple colnames. Returns a new table with only those columns and their rows. Useful when using Rex to filter output, prep CSV, etc. Testing: ``` t = Rex::Ui::Text::Table.new('Columns' => ['a','b','c']) t << ['x','y','z'] t << ['p','q','r'] t['a','c'] => a c - - p r x z ``` --- lib/rex/ui/text/table.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/rex/ui/text/table.rb b/lib/rex/ui/text/table.rb index 56ca8a61a7..a7fc917082 100644 --- a/lib/rex/ui/text/table.rb +++ b/lib/rex/ui/text/table.rb @@ -212,6 +212,24 @@ class Table rows << '__hr__' end + # + # Returns new sub-table with headers and rows maching column names submitted + # + def [](*colnames) + tbl = self.class.new('Indent' => self.indent,'Header' => self.header,'Columns' => colnames) + idx = [] + colnames.each do |colname| + idx << self.columns.index(colname) + end + self.rows.each do |oldrow| + newrow = [] + idx.map {|i| newrow << oldrow[i]} + tbl << newrow + end + return tbl + end + + alias p print attr_accessor :header, :headeri # :nodoc: From 0adb30c87a5d15bafaa71ab3381adb4991566a5f Mon Sep 17 00:00:00 2001 From: RageLtMan Date: Thu, 28 Mar 2013 04:11:52 -0400 Subject: [PATCH 2/6] whitespace cleanup --- lib/rex/ui/text/table.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/rex/ui/text/table.rb b/lib/rex/ui/text/table.rb index a7fc917082..4ec5568dad 100644 --- a/lib/rex/ui/text/table.rb +++ b/lib/rex/ui/text/table.rb @@ -212,22 +212,22 @@ class Table rows << '__hr__' end - # + # # Returns new sub-table with headers and rows maching column names submitted - # + # def [](*colnames) tbl = self.class.new('Indent' => self.indent,'Header' => self.header,'Columns' => colnames) idx = [] colnames.each do |colname| idx << self.columns.index(colname) - end + end self.rows.each do |oldrow| newrow = [] idx.map {|i| newrow << oldrow[i]} tbl << newrow - end - return tbl - end + end + return tbl + end alias p print From 3c1df47314c467b5a701714d7211f8c4c8e0f7e8 Mon Sep 17 00:00:00 2001 From: Tab Assassin Date: Thu, 5 Sep 2013 16:10:40 -0500 Subject: [PATCH 3/6] Retab changes for PR #1681 --- lib/rex/ui/text/table.rb | 362 +++++++++++++++++++-------------------- 1 file changed, 181 insertions(+), 181 deletions(-) diff --git a/lib/rex/ui/text/table.rb b/lib/rex/ui/text/table.rb index d622ce3209..e4da73e656 100644 --- a/lib/rex/ui/text/table.rb +++ b/lib/rex/ui/text/table.rb @@ -14,203 +14,203 @@ module Text ### class Table - # - # Initializes a text table instance using the supplied properties. The - # Table class supports the following hash attributes: - # - # Header - # - # The string to display as a heading above the table. If none is - # specified, no header will be displayed. - # - # HeaderIndent - # - # The amount of space to indent the header. The default is zero. - # - # Columns - # - # The array of columns that will exist within the table. - # - # Rows - # - # The array of rows that will exist. - # - # Width - # - # The maximum width of the table in characters. - # - # Indent - # - # The number of characters to indent the table. - # - # CellPad - # - # The number of characters to put between each horizontal cell. - # - # Prefix - # - # The text to prefix before the table. - # - # Postfix - # - # The text to affix to the end of the table. - # - # Sortindex - # - # The column to sort the table on, -1 disables sorting. - # - def initialize(opts = {}) - self.header = opts['Header'] - self.headeri = opts['HeaderIndent'] || 0 - self.columns = opts['Columns'] || [] - # updated below if we got a "Rows" option - self.rows = [] + # + # Initializes a text table instance using the supplied properties. The + # Table class supports the following hash attributes: + # + # Header + # + # The string to display as a heading above the table. If none is + # specified, no header will be displayed. + # + # HeaderIndent + # + # The amount of space to indent the header. The default is zero. + # + # Columns + # + # The array of columns that will exist within the table. + # + # Rows + # + # The array of rows that will exist. + # + # Width + # + # The maximum width of the table in characters. + # + # Indent + # + # The number of characters to indent the table. + # + # CellPad + # + # The number of characters to put between each horizontal cell. + # + # Prefix + # + # The text to prefix before the table. + # + # Postfix + # + # The text to affix to the end of the table. + # + # Sortindex + # + # The column to sort the table on, -1 disables sorting. + # + def initialize(opts = {}) + self.header = opts['Header'] + self.headeri = opts['HeaderIndent'] || 0 + self.columns = opts['Columns'] || [] + # updated below if we got a "Rows" option + self.rows = [] - self.width = opts['Width'] || 80 - self.indent = opts['Indent'] || 0 - self.cellpad = opts['CellPad'] || 2 - self.prefix = opts['Prefix'] || '' - self.postfix = opts['Postfix'] || '' - self.colprops = [] + self.width = opts['Width'] || 80 + self.indent = opts['Indent'] || 0 + self.cellpad = opts['CellPad'] || 2 + self.prefix = opts['Prefix'] || '' + self.postfix = opts['Postfix'] || '' + self.colprops = [] - self.sort_index = opts['SortIndex'] || 0 + self.sort_index = opts['SortIndex'] || 0 - # Default column properties - self.columns.length.times { |idx| - self.colprops[idx] = {} - self.colprops[idx]['MaxWidth'] = self.columns[idx].length - } + # Default column properties + self.columns.length.times { |idx| + self.colprops[idx] = {} + self.colprops[idx]['MaxWidth'] = self.columns[idx].length + } - # ensure all our internal state gets updated with the given rows by - # using add_row instead of just adding them to self.rows. See #3825. - opts['Rows'].each { |row| add_row(row) } if opts['Rows'] + # ensure all our internal state gets updated with the given rows by + # using add_row instead of just adding them to self.rows. See #3825. + opts['Rows'].each { |row| add_row(row) } if opts['Rows'] - # Merge in options - if (opts['ColProps']) - opts['ColProps'].each_key { |col| - idx = self.columns.index(col) + # Merge in options + if (opts['ColProps']) + opts['ColProps'].each_key { |col| + idx = self.columns.index(col) - if (idx) - self.colprops[idx].merge!(opts['ColProps'][col]) - end - } - end + if (idx) + self.colprops[idx].merge!(opts['ColProps'][col]) + end + } + end - end + end - # - # Converts table contents to a string. - # - def to_s - str = prefix.dup - str << header_to_s || '' - str << columns_to_s || '' - str << hr_to_s || '' + # + # Converts table contents to a string. + # + def to_s + str = prefix.dup + str << header_to_s || '' + str << columns_to_s || '' + str << hr_to_s || '' - sort_rows - rows.each { |row| - if (is_hr(row)) - str << hr_to_s - else - str << row_to_s(row) - end - } + sort_rows + rows.each { |row| + if (is_hr(row)) + str << hr_to_s + else + str << row_to_s(row) + end + } - str << postfix + str << postfix - return str - end + return str + end - # - # Converts table contents to a csv - # - def to_csv - str = '' - str << ( columns.join(",") + "\n" ) - rows.each { |row| - next if is_hr(row) - str << ( row.map{|x| - x = x.to_s + # + # Converts table contents to a csv + # + def to_csv + str = '' + str << ( columns.join(",") + "\n" ) + rows.each { |row| + next if is_hr(row) + str << ( row.map{|x| + x = x.to_s - x.gsub(/[\r\n]/, ' ').gsub(/\s+/, ' ').gsub('"', '""') - }.map{|x| "\"#{x}\"" }.join(",") + "\n" ) - } - str - end + x.gsub(/[\r\n]/, ' ').gsub(/\s+/, ' ').gsub('"', '""') + }.map{|x| "\"#{x}\"" }.join(",") + "\n" ) + } + str + end - # - # - # Returns the header string. - # - def header_to_s # :nodoc: - if (header) - pad = " " * headeri + # + # + # Returns the header string. + # + def header_to_s # :nodoc: + if (header) + pad = " " * headeri - return pad + header + "\n" + pad + "=" * header.length + "\n\n" - end + return pad + header + "\n" + pad + "=" * header.length + "\n\n" + end - return '' - end + return '' + end - # - # Prints the contents of the table. - # - def print - puts to_s - end + # + # Prints the contents of the table. + # + def print + puts to_s + end - # - # Adds a row using the supplied fields. - # - def <<(fields) - add_row(fields) - end + # + # Adds a row using the supplied fields. + # + def <<(fields) + add_row(fields) + end - # - # Adds a row with the supplied fields. - # - def add_row(fields = []) - if fields.length != self.columns.length - raise RuntimeError, 'Invalid number of columns!' - end - fields.each_with_index { |field, idx| - if (colprops[idx]['MaxWidth'] < field.to_s.length) - colprops[idx]['MaxWidth'] = field.to_s.length - end - } + # + # Adds a row with the supplied fields. + # + def add_row(fields = []) + if fields.length != self.columns.length + raise RuntimeError, 'Invalid number of columns!' + end + fields.each_with_index { |field, idx| + if (colprops[idx]['MaxWidth'] < field.to_s.length) + colprops[idx]['MaxWidth'] = field.to_s.length + end + } - rows << fields - end + rows << fields + end - # - # Sorts the rows based on the supplied index of sub-arrays - # If the supplied index is an IPv4 address, handle it differently, but - # avoid actually resolving domain names. - # - def sort_rows(index=sort_index) - return if index == -1 - return unless rows - rows.sort! do |a,b| - if a[index].nil? - -1 - elsif b[index].nil? - 1 - elsif Rex::Socket.dotted_ip?(a[index]) and Rex::Socket.dotted_ip?(b[index]) - Rex::Socket::addr_atoi(a[index]) <=> Rex::Socket::addr_atoi(b[index]) - elsif a[index] =~ /^[0-9]+$/ and b[index] =~ /^[0-9]+$/ - a[index].to_i <=> b[index].to_i - else - a[index] <=> b[index] # assumes otherwise comparable. - end - end - end + # + # Sorts the rows based on the supplied index of sub-arrays + # If the supplied index is an IPv4 address, handle it differently, but + # avoid actually resolving domain names. + # + def sort_rows(index=sort_index) + return if index == -1 + return unless rows + rows.sort! do |a,b| + if a[index].nil? + -1 + elsif b[index].nil? + 1 + elsif Rex::Socket.dotted_ip?(a[index]) and Rex::Socket.dotted_ip?(b[index]) + Rex::Socket::addr_atoi(a[index]) <=> Rex::Socket::addr_atoi(b[index]) + elsif a[index] =~ /^[0-9]+$/ and b[index] =~ /^[0-9]+$/ + a[index].to_i <=> b[index].to_i + else + a[index] <=> b[index] # assumes otherwise comparable. + end + end + end - # - # Adds a horizontal line. - # - def add_hr - rows << '__hr__' - end + # + # Adds a horizontal line. + # + def add_hr + rows << '__hr__' + end # # Returns new sub-table with headers and rows maching column names submitted @@ -230,13 +230,13 @@ class Table end - alias p print + alias p print - attr_accessor :header, :headeri # :nodoc: - attr_accessor :columns, :rows, :colprops # :nodoc: - attr_accessor :width, :indent, :cellpad # :nodoc: - attr_accessor :prefix, :postfix # :nodoc: - attr_accessor :sort_index # :nodoc: + attr_accessor :header, :headeri # :nodoc: + attr_accessor :columns, :rows, :colprops # :nodoc: + attr_accessor :width, :indent, :cellpad # :nodoc: + attr_accessor :prefix, :postfix # :nodoc: + attr_accessor :sort_index # :nodoc: protected From 6a13a0eee67ec7cc2e9457082eea08db599bcb97 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Tue, 19 Nov 2013 15:42:12 -0600 Subject: [PATCH 4/6] fix indentation --- lib/rex/ui/text/table.rb | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/rex/ui/text/table.rb b/lib/rex/ui/text/table.rb index e4da73e656..9fada23587 100644 --- a/lib/rex/ui/text/table.rb +++ b/lib/rex/ui/text/table.rb @@ -212,22 +212,22 @@ class Table rows << '__hr__' end - # - # Returns new sub-table with headers and rows maching column names submitted - # - def [](*colnames) - tbl = self.class.new('Indent' => self.indent,'Header' => self.header,'Columns' => colnames) - idx = [] - colnames.each do |colname| - idx << self.columns.index(colname) - end - self.rows.each do |oldrow| - newrow = [] - idx.map {|i| newrow << oldrow[i]} - tbl << newrow - end - return tbl - end + # + # Returns new sub-table with headers and rows maching column names submitted + # + def [](*colnames) + tbl = self.class.new('Indent' => self.indent,'Header' => self.header,'Columns' => colnames) + idx = [] + colnames.each do |colname| + idx << self.columns.index(colname) + end + self.rows.each do |oldrow| + newrow = [] + idx.map {|i| newrow << oldrow[i]} + tbl << newrow + end + return tbl + end alias p print From 162d433014316a3bf11cc84890817892f8a0a96b Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Tue, 19 Nov 2013 15:46:11 -0600 Subject: [PATCH 5/6] Use snake_case for variables --- lib/rex/ui/text/table.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/rex/ui/text/table.rb b/lib/rex/ui/text/table.rb index 9fada23587..fff8ffd8a5 100644 --- a/lib/rex/ui/text/table.rb +++ b/lib/rex/ui/text/table.rb @@ -215,16 +215,16 @@ class Table # # Returns new sub-table with headers and rows maching column names submitted # - def [](*colnames) - tbl = self.class.new('Indent' => self.indent,'Header' => self.header,'Columns' => colnames) + def [](*col_names) + tbl = self.class.new('Indent' => self.indent,'Header' => self.header,'Columns' => col_names) idx = [] - colnames.each do |colname| - idx << self.columns.index(colname) + col_names.each do |col_name| + idx << self.columns.index(col_name) end - self.rows.each do |oldrow| - newrow = [] - idx.map {|i| newrow << oldrow[i]} - tbl << newrow + self.rows.each do |old_row| + new_row = [] + idx.map {|i| new_row << old_row[i]} + tbl << new_row end return tbl end From e1eddc84aad5811ad08ba63e4ed63f6fa757b0f5 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Tue, 19 Nov 2013 16:02:52 -0600 Subject: [PATCH 6/6] Check for inexistent column names --- lib/rex/ui/text/table.rb | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/rex/ui/text/table.rb b/lib/rex/ui/text/table.rb index fff8ffd8a5..962c7caed8 100644 --- a/lib/rex/ui/text/table.rb +++ b/lib/rex/ui/text/table.rb @@ -216,16 +216,23 @@ class Table # Returns new sub-table with headers and rows maching column names submitted # def [](*col_names) - tbl = self.class.new('Indent' => self.indent,'Header' => self.header,'Columns' => col_names) - idx = [] + tbl = self.class.new('Indent' => self.indent, + 'Header' => self.header, + 'Columns' => col_names) + indexes = [] + col_names.each do |col_name| - idx << self.columns.index(col_name) + index = self.columns.index(col_name) + raise RuntimeError, "Invalid column name #{col_name}" if index.nil? + indexes << index end + self.rows.each do |old_row| new_row = [] - idx.map {|i| new_row << old_row[i]} + indexes.map {|i| new_row << old_row[i]} tbl << new_row end + return tbl end