glark 1.9.0 → 1.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. data/bin/glark +2 -2
  2. data/lib/glark.rb +1 -1
  3. data/lib/glark/app/app.rb +48 -0
  4. data/lib/glark/app/help.rb +103 -0
  5. data/lib/glark/app/info/options.rb +84 -0
  6. data/lib/glark/app/options.rb +201 -0
  7. data/lib/glark/app/rcfile.rb +49 -0
  8. data/lib/glark/app/runner.rb +140 -0
  9. data/lib/glark/app/spec.rb +19 -0
  10. data/lib/glark/input/filter/criteria_opts.rb +41 -0
  11. data/lib/glark/input/filter/dir_criteria_opts.rb +37 -0
  12. data/lib/glark/input/filter/file_criteria_opts.rb +33 -0
  13. data/lib/glark/input/filter/filter.rb +59 -0
  14. data/lib/glark/input/filter/options.rb +171 -0
  15. data/lib/glark/input/options.rb +120 -0
  16. data/lib/glark/input/range.rb +104 -0
  17. data/lib/glark/input/spec.rb +39 -0
  18. data/lib/glark/io/file/archive_file.rb +64 -0
  19. data/lib/glark/io/file/binary_file.rb +19 -0
  20. data/lib/glark/io/file/file.rb +57 -0
  21. data/lib/glark/io/file/gz_file.rb +21 -0
  22. data/lib/glark/io/file/tar_file.rb +35 -0
  23. data/lib/glark/io/file/tar_gz_file.rb +52 -0
  24. data/lib/glark/io/file/zip_file.rb +39 -0
  25. data/lib/glark/match/and.rb +83 -0
  26. data/lib/glark/match/and_distance.rb +58 -0
  27. data/lib/glark/match/compound.rb +34 -0
  28. data/lib/glark/match/expression.rb +63 -0
  29. data/lib/glark/match/factory.rb +173 -0
  30. data/lib/glark/match/ior.rb +20 -0
  31. data/lib/glark/match/options.rb +74 -0
  32. data/lib/glark/match/or.rb +41 -0
  33. data/lib/glark/match/re.rb +81 -0
  34. data/lib/glark/match/re_factory.rb +44 -0
  35. data/lib/glark/match/spec.rb +59 -0
  36. data/lib/glark/match/xor.rb +20 -0
  37. data/lib/glark/output/binary_file_summary.rb +17 -0
  38. data/lib/glark/output/common.rb +43 -0
  39. data/lib/glark/output/context.rb +57 -0
  40. data/lib/glark/output/count.rb +26 -0
  41. data/lib/glark/output/file_header.rb +20 -0
  42. data/lib/glark/output/file_name_only.rb +35 -0
  43. data/lib/glark/output/formatted.rb +22 -0
  44. data/lib/glark/output/glark_count.rb +23 -0
  45. data/lib/glark/output/glark_format.rb +62 -0
  46. data/lib/glark/output/glark_lines.rb +36 -0
  47. data/lib/glark/output/grep_count.rb +18 -0
  48. data/lib/glark/output/grep_lines.rb +42 -0
  49. data/lib/glark/output/line_status.rb +46 -0
  50. data/lib/glark/output/lines.rb +100 -0
  51. data/lib/glark/output/match_list.rb +15 -0
  52. data/lib/glark/output/options.rb +103 -0
  53. data/lib/glark/output/results.rb +23 -0
  54. data/lib/glark/output/spec.rb +105 -0
  55. data/lib/glark/output/unfiltered_lines.rb +28 -0
  56. data/lib/glark/util/colors/options.rb +143 -0
  57. data/lib/glark/util/colors/spec.rb +21 -0
  58. data/lib/glark/util/highlight.rb +108 -0
  59. data/lib/glark/util/io/depth.rb +29 -0
  60. data/lib/glark/util/io/fileset.rb +162 -0
  61. data/lib/glark/util/io/filter/criteria.rb +49 -0
  62. data/lib/glark/util/io/filter/filter.rb +10 -0
  63. data/lib/glark/util/io/lines.rb +117 -0
  64. data/lib/glark/util/option.rb +34 -0
  65. data/lib/glark/util/options.rb +12 -0
  66. data/lib/glark/util/optutil.rb +69 -0
  67. data/lib/glark/util/timestamper.rb +18 -0
  68. data/man/glark.1 +1134 -0
  69. data/test/glark/app/and_test.rb +82 -0
  70. data/test/glark/app/compound_test.rb +33 -0
  71. data/test/glark/app/context_test.rb +43 -0
  72. data/test/glark/app/count_test.rb +89 -0
  73. data/test/glark/app/dump_test.rb +16 -0
  74. data/test/glark/app/expression_file_test.rb +22 -0
  75. data/test/glark/app/extended_regexp_test.rb +17 -0
  76. data/test/glark/app/extract_matches_test.rb +27 -0
  77. data/test/glark/app/files_with_match_test.rb +32 -0
  78. data/test/glark/app/files_without_match_test.rb +26 -0
  79. data/test/glark/app/filter_test.rb +118 -0
  80. data/test/glark/app/highlight_test.rb +78 -0
  81. data/test/glark/app/ignore_case_test.rb +22 -0
  82. data/test/glark/app/invert_test.rb +49 -0
  83. data/test/glark/app/ior_test.rb +21 -0
  84. data/test/glark/app/label_test.rb +28 -0
  85. data/test/glark/app/line_number_color_test.rb +42 -0
  86. data/test/glark/app/line_numbers_test.rb +42 -0
  87. data/test/glark/app/match_limit_test.rb +49 -0
  88. data/test/glark/app/options_test.rb +722 -0
  89. data/test/glark/app/range_test.rb +101 -0
  90. data/test/glark/app/rcfile_test.rb +113 -0
  91. data/test/glark/app/record_separator_test.rb +32 -0
  92. data/test/glark/app/regexp_test.rb +48 -0
  93. data/test/glark/app/tc.rb +92 -0
  94. data/test/glark/app/text_color_test.rb +31 -0
  95. data/test/glark/app/whole_lines_test.rb +17 -0
  96. data/test/glark/app/whole_words_test.rb +42 -0
  97. data/test/glark/app/xor_test.rb +19 -0
  98. data/test/glark/input/binary_file_test.rb +0 -0
  99. data/test/glark/input/directory_test.rb +202 -0
  100. data/test/glark/input/dirname_test.rb +69 -0
  101. data/test/glark/input/exclude_matching_test.rb +20 -0
  102. data/test/glark/input/ext_test.rb +65 -0
  103. data/test/glark/input/filter/criteria_test.rb +91 -0
  104. data/test/glark/input/filter/filter_spec_test.rb +27 -0
  105. data/test/glark/input/filter/filter_test.rb +21 -0
  106. data/test/glark/input/name_test.rb +75 -0
  107. data/test/glark/input/path_test.rb +72 -0
  108. data/test/glark/input/range_test.rb +82 -0
  109. data/test/glark/input/size_limit_test.rb +51 -0
  110. data/test/glark/input/split_as_path_test.rb +28 -0
  111. data/test/glark/match_test.rb +192 -0
  112. data/test/glark/resources.rb +21 -0
  113. data/test/glark/tc.rb +37 -0
  114. data/test/resources/add.rb +10 -0
  115. data/test/resources/echo.rb +2 -0
  116. data/test/resources/greet.rb +13 -0
  117. metadata +198 -28
  118. data/README +0 -0
  119. data/bin/jlark +0 -63
  120. data/lib/glark/expression.rb +0 -440
  121. data/lib/glark/exprfactory.rb +0 -248
  122. data/lib/glark/glark.rb +0 -297
  123. data/lib/glark/help.rb +0 -85
  124. data/lib/glark/input.rb +0 -183
  125. data/lib/glark/options.rb +0 -757
  126. data/lib/glark/output.rb +0 -266
  127. data/test/lib/glark/glark_test.rb +0 -317
  128. data/test/lib/glark/options_test.rb +0 -891
data/lib/glark/help.rb DELETED
@@ -1,85 +0,0 @@
1
- #!/usr/bin/ruby -w
2
- # -*- ruby -*-
3
-
4
- # Glark help.
5
-
6
- class GlarkHelp
7
-
8
- def initialize
9
- puts "Usage: glark [options] expression file..."
10
- puts "Search for expression in each file or standard input."
11
- puts "Example: glark --and=3 'try' 'catch' *.java"
12
- puts ""
13
-
14
- puts "Input:"
15
- puts " -0[nnn] Use \\nnn as the input record separator"
16
- puts " -d, --directories=ACTION Process directories as read, skip, or recurse"
17
- puts " --binary-files=TYPE Treat binary files as TYPE"
18
- puts " --[with-]basename, "
19
- puts " --[with-]name EXPR Search only files with base names matching EXPR"
20
- puts " --without-basename, "
21
- puts " --without-name EXPR Ignore files with base names matching EXPR"
22
- puts " --[with-]fullname, "
23
- puts " --[with-]path EXPR Search only files with full names matching EXPR"
24
- puts " --without-fullname, "
25
- puts " --without-path EXPR Ignore files with full names matching EXPR"
26
- puts " -M, --exclude-matching Ignore files with names matching the expression"
27
- puts " -r, --recurse Recurse through directories"
28
- puts " --size-limit=SIZE Search only files no larger than SIZE"
29
- puts ""
30
-
31
- puts "Matching:"
32
- puts " -a, --and=NUM EXPR1 EXPR2 Match both expressions, within NUM lines"
33
- puts " -b, --before NUM[%] Restrict the search to the top % or lines"
34
- puts " --after NUM[%] Restrict the search to after the given location"
35
- puts " -f, --file=FILE Use the lines in the given file as expressions"
36
- puts " -i, --ignore-case Ignore case for matching regular expressions"
37
- puts " -m, --match-limit=NUM Find only the first NUM matches in each file"
38
- puts " -o, --or EXPR1 EXPR2 Match either of the two expressions"
39
- puts " -R, --range NUM[%] NUM[%] Restrict the search to the given range of lines"
40
- puts " -v, --invert-match Show lines not matching the expression"
41
- puts " -w, --word, --word-regexp Put word boundaries around each pattern"
42
- puts " -x, --line-regexp Select entire line matching pattern"
43
- puts " --xor EXPR1 EXPR2 Match either expression, but not both"
44
- puts ""
45
-
46
- puts "Output:"
47
- puts " -A, --after-context=NUM Print NUM lines of trailing context"
48
- puts " -B, --before-context=NUM Print NUM lines of leading context"
49
- puts " -C, -NUM, --context[=NUM] Output NUM lines of context"
50
- puts " -c, --count Display only the match count per file"
51
- puts " -F, --file-color COLOR Specify the highlight color for file names"
52
- puts " --no-filter Display the entire file"
53
- puts " -g, --grep Produce output like the grep default"
54
- puts " -h, --no-filename Do not display the names of matching files"
55
- puts " -H, --with-filename Display the names of matching files"
56
- puts " -l, --files-with-matches Print only names of matching file"
57
- puts " -L, --files-without-match Print only names of file not matching"
58
- puts " --label=NAME Use NAME as output file name"
59
- puts " -n, --line-number Display line numbers"
60
- puts " -N, --no-line-number Do not display line numbers"
61
- puts " --line-number-color COLOR Specify the highlight color for line numbers"
62
- # puts " --output=FORMAT Produce output in the format (ansi, grep)"
63
- puts " -T, --text-color COLOR Specify the highlight color for text"
64
- puts " --text-color-NUM COLOR Specify the highlight color for regexp capture NUM"
65
- puts " -u, --highlight[=FORMAT] Enable highlighting. Format is single or multi"
66
- puts " -U, --no-highlight Disable highlighting"
67
- puts " -y, --extract-matches Display only the matching region, not the entire line"
68
- puts " -Z, --null In -l mode, write file names followed by NULL"
69
- puts ""
70
-
71
- puts "Debugging/Errors:"
72
- puts " --conf Write the current options in RC file format"
73
- puts " --dump Write all options and expressions"
74
- puts " --explain Write the expression in a more legible format"
75
- puts " -q, --quiet Suppress warnings"
76
- puts " -Q, --no-quiet Enable warnings"
77
- puts " -s, --no-messages Suppress warnings"
78
- puts " -V, --version Display version information"
79
- puts " --verbose Display normally suppressed output"
80
-
81
- puts ""
82
- puts "See the man page for more information."
83
- end
84
-
85
- end
data/lib/glark/input.rb DELETED
@@ -1,183 +0,0 @@
1
- #!/usr/bin/ruby -w
2
- #!ruby -w
3
- # vim: set filetype=ruby : set sw=2
4
-
5
- # Glark input.
6
-
7
- require 'rubygems'
8
- require 'riel'
9
-
10
- # A thing that can be grepped.
11
- class InputFile
12
- include Loggable
13
-
14
- attr_reader :fname, :stati
15
- attr_accessor :count, :output, :invert_match
16
-
17
- # cross-platform end of line: DOS UNIX MAC
18
- ANY_END_OF_LINE = Regexp.new('(?:\r\n|\n|\r)')
19
-
20
- WRITTEN = "written"
21
-
22
- def initialize(fname, io, args = GlarkOptions.instance)
23
- @fname = fname
24
- @io = io
25
- @stati = Array.new # index = line number, value = context character
26
- @count = nil
27
- @extracted = nil
28
- @regions = nil
29
- @modlines = nil
30
- @invert_match = false
31
- @linecount = nil
32
- @readall = $/ != "\n"
33
- @lines = @readall ? IO.readlines(@fname) : Array.new
34
-
35
- @after = args[:after]
36
- @before = args[:before]
37
- @output = args[:output]
38
-
39
- @matched = false
40
- end
41
-
42
- def linecount
43
- @linecount ||= begin
44
- IO.readlines(@fname).size
45
- end
46
- end
47
-
48
- def matched?
49
- @matched
50
- end
51
-
52
- def each_line
53
- if @readall
54
- @lines.each do |line|
55
- yield line
56
- end
57
- else
58
- while (line = @io.gets) && line.length > 0
59
- @lines << line
60
- yield line
61
- end
62
- end
63
- end
64
-
65
- def set_status(from, to, ch, force = false)
66
- from.upto(to) do |ln|
67
- if (not @stati[ln]) || (@stati[ln] != WRITTEN && force)
68
- @stati[ln] = ch
69
- end
70
- end
71
- end
72
-
73
- def mark_as_match(start_line, end_line = start_line)
74
- @matched = true
75
-
76
- # even with multi-line matches (--and expressions), we'll display
77
- # only the first matching line, not the range between the matches.
78
-
79
- if @output == "grep"
80
- end_line = start_line
81
- end
82
-
83
- if @count
84
- @count += 1
85
- else
86
- st = [0, start_line - @before].max
87
- set_status(st, start_line - 1, "-")
88
- set_status(start_line, end_line, ":", true)
89
- set_status(end_line + 1, end_line + @after, "+")
90
- end
91
- end
92
-
93
- def write_matches(matching, from = nil, to = nil)
94
- @output.write_matches(matching, from, to)
95
- end
96
-
97
- def write_all
98
- @output.write_all
99
- end
100
-
101
- # Returns the lines for this file, separated by end of line sequences.
102
- def get_lines
103
- if $/ == "\n"
104
- @lines
105
- else
106
- @extracted ||= begin
107
- # This is much easier. Just resplit the whole thing at end of line
108
- # sequences.
109
-
110
- eoline = "\n" # should be OS-dependent
111
- srclines = @lines
112
- reallines = @lines.join("").split(ANY_END_OF_LINE)
113
-
114
- # "\n" after all but the last line
115
- extracted = (0 ... (reallines.length - 1)).collect do |lnum|
116
- reallines[lnum] + eoline
117
- end
118
- extracted << reallines[-1]
119
-
120
- if Log.verbose
121
- extracted.each_with_index do |line, idx|
122
- log "extracted[#{idx}]: #{@extracted[idx]}"
123
- end
124
- end
125
- extracted
126
- end
127
- end
128
- end
129
-
130
- # Returns the given line for this file. For this method, a line ends with a
131
- # CR, as opposed to the "lines" method, which ends with $/.
132
- def get_line(lnum)
133
- log { "lnum: #{lnum}" }
134
- ln = get_lines()[lnum]
135
- log { "ln: #{ln}" }
136
- ln
137
- end
138
-
139
- # returns the range that is represented by the region number
140
- def get_range(rnum)
141
- if $/ == "\n"
142
- # easy case: range is the range number, unless it is out of range.
143
- rnum < @lines.length ? (rnum .. rnum) : nil
144
- else
145
- unless @regions
146
- srclines = @modlines ? @modlines : @lines
147
-
148
- @regions = [] # keys = region number; values = range of lines
149
-
150
- lstart = 0
151
- srclines.each do |line|
152
- lend = lstart
153
- line.scan(ANY_END_OF_LINE).each do |cr|
154
- lend += 1
155
- end
156
-
157
- @regions << Range.new(lstart, lend - 1)
158
-
159
- lstart = lend
160
- end
161
- end
162
-
163
- @regions[rnum]
164
- end
165
- end
166
- end
167
-
168
-
169
- # -------------------------------------------------------
170
- # Binary input file
171
- # -------------------------------------------------------
172
-
173
- class BinaryFile < InputFile
174
-
175
- def write_matches(matching, from, to)
176
- if count
177
- write_count(matching)
178
- else
179
- puts "Binary file " + @fname + " matches"
180
- end
181
- end
182
-
183
- end
data/lib/glark/options.rb DELETED
@@ -1,757 +0,0 @@
1
- #!/usr/bin/ruby -w
2
- # -*- ruby -*-
3
-
4
- require 'pathname'
5
-
6
- require 'rubygems'
7
- require 'riel/text'
8
- require 'riel/log'
9
- require 'riel/env'
10
- require 'riel/optproc'
11
- require 'riel'
12
-
13
-
14
- # -------------------------------------------------------
15
- # Options
16
- # -------------------------------------------------------
17
-
18
- class GlarkInputOptions
19
- include Loggable, Singleton
20
-
21
- end
22
-
23
-
24
- class GlarkOptions
25
- include Loggable, Singleton
26
-
27
- attr_accessor :after
28
- attr_accessor :before
29
- attr_accessor :binary_files
30
- attr_accessor :count
31
- attr_accessor :directory
32
- attr_accessor :exclude_matching
33
- attr_accessor :explain
34
- attr_accessor :expr
35
- attr_accessor :extended
36
- attr_accessor :extract_matches
37
- attr_accessor :file_highlight
38
- attr_accessor :file_names_only
39
- attr_accessor :filter
40
- attr_accessor :highlight
41
- attr_accessor :highlighter
42
- attr_accessor :invert_match
43
- attr_accessor :label
44
- attr_accessor :line_number_highlight
45
- attr_accessor :local_config_files
46
- attr_accessor :match_limit
47
- attr_accessor :multiline
48
- attr_accessor :nocase
49
- attr_accessor :out
50
- attr_accessor :output
51
- attr_accessor :quiet
52
- attr_accessor :range_end
53
- attr_accessor :range_start
54
- attr_accessor :show_break
55
- attr_accessor :show_file_names
56
- attr_accessor :show_line_numbers
57
- attr_accessor :size_limit
58
- attr_accessor :split_as_path
59
- attr_accessor :text_highlights
60
- attr_accessor :verbose
61
- attr_accessor :version
62
- attr_accessor :whole_lines
63
- attr_accessor :whole_words
64
- attr_accessor :with_basename
65
- attr_accessor :with_fullname
66
- attr_accessor :without_basename
67
- attr_accessor :without_fullname
68
- attr_accessor :write_null
69
-
70
- def initialize
71
- optdata = [
72
- {
73
- :tags => %w{ -C --context },
74
- :res => %r{ ^ - ([1-9]\d*) $ }x,
75
- :arg => [ :optional, :integer ],
76
- :set => Proc.new { |val, opt, args| @after = @before = val || 2 },
77
- :rc => %w{ context },
78
- },
79
- {
80
- :tags => %w{ --after-context -A },
81
- :arg => [ :integer ],
82
- :set => Proc.new { |val| @after = val },
83
- :rc => %w{ after-context },
84
- },
85
- {
86
- :tags => %w{ --before-context -B },
87
- :arg => [ :integer ],
88
- :set => Proc.new { |val| @before = val },
89
- :rc => %w{ before-context },
90
- },
91
- {
92
- :tags => %w{ -V --version },
93
- :set => Proc.new { show_version }
94
- },
95
- {
96
- :tags => %w{ --verbose --verbosity },
97
- :arg => [ :integer, :optional ],
98
- :set => Proc.new { |val| Log.verbose = val || 1 }
99
- },
100
- {
101
- :tags => %w{ -v --invert-match },
102
- :set => Proc.new { @invert_match = true }
103
- },
104
- {
105
- :tags => %w{ -i --ignore-case },
106
- :set => Proc.new { @nocase = true }
107
- },
108
- {
109
- :tags => %w{ --filter },
110
- :set => Proc.new { @filter = true }
111
- },
112
- {
113
- :tags => %w{ --no-filter --nofilter },
114
- :set => Proc.new { @filter = false }
115
- },
116
- {
117
- :tags => %w{ -U --no-highlight },
118
- :set => Proc.new { set_highlight(nil) }
119
- },
120
- {
121
- :tags => %w{ -g --grep },
122
- :set => Proc.new { set_output_style("grep") }
123
- },
124
- {
125
- :tags => %w{ -? --help },
126
- :set => Proc.new { require 'glark/help'; GlarkHelp.new; exit 0 }
127
- },
128
- {
129
- :tags => %w{ --explain },
130
- :set => Proc.new { @explain = true }
131
- },
132
- {
133
- :tags => %w{ -n --line-number },
134
- :set => Proc.new { @show_line_numbers = true }
135
- },
136
- {
137
- :tags => %w{ -N --no-line-number },
138
- :set => Proc.new { @show_line_numbers = false }
139
- },
140
- {
141
- :tags => %w{ --line-number-color },
142
- :arg => [ :string ],
143
- :set => Proc.new { |val| @line_number_highlight = make_highlight("line-number-color", val) },
144
- },
145
- {
146
- :tags => %w{ -q -s --quiet --messages },
147
- :set => Proc.new { Log.quiet = @quiet = true }
148
- },
149
- {
150
- :tags => %w{ -Q -S --no-quiet --no-messages },
151
- :set => Proc.new { Log.quiet = @quiet = false }
152
- },
153
- {
154
- :tags => %w{ -w --word --word-regexp },
155
- :set => Proc.new { @whole_words = true }
156
- },
157
- {
158
- :tags => %w{ -x --line-regexp },
159
- :set => Proc.new { @whole_lines = true }
160
- },
161
- {
162
- :tags => %w{ -l --files-with-matches },
163
- :set => Proc.new { @file_names_only = true; @invert_match = false }
164
- },
165
- {
166
- :tags => %w{ -L --files-without-match },
167
- :set => Proc.new { @file_names_only = true; @invert_match = true }
168
- },
169
- {
170
- :tags => %w{ --extended },
171
- :set => Proc.new { @extended = true }
172
- },
173
- {
174
- :tags => %w{ --multiline },
175
- :set => Proc.new { @multiline = true }
176
- },
177
- {
178
- :tags => %w{ -c --count },
179
- :set => Proc.new { @count = true }
180
- },
181
- {
182
- :tags => %w{ -Z --null },
183
- :set => Proc.new { @write_null = true }
184
- },
185
- {
186
- :tags => %w{ -M --exclude-matching },
187
- :set => Proc.new { @exclude_matching = true }
188
- },
189
- {
190
- :tags => %w{ -d },
191
- :arg => [ :string ],
192
- :set => Proc.new { |val| @directory = val }
193
- },
194
- {
195
- :tags => %w{ -r --recurse },
196
- :set => Proc.new { @directory = "recurse" }
197
- },
198
- {
199
- :tags => %w{ -y --extract-matches },
200
- :set => Proc.new { @extract_matches = true }
201
- },
202
- {
203
- :tags => %w{ --conf },
204
- :set => Proc.new { write_configuration; exit }
205
- },
206
- {
207
- :tags => %w{ --dump },
208
- :set => Proc.new { dump_all_fields; exit 0 }
209
- },
210
- {
211
- :tags => %w{ --no-split-as-path },
212
- :set => Proc.new { @split_as_path = false }
213
- },
214
- {
215
- :tags => %w{ --split-as-path },
216
- :arg => [ :boolean, :optional ],
217
- :set => Proc.new { |val| @split_as_path = val }
218
- },
219
- {
220
- :tags => %w{ --directories },
221
- :arg => [ :string ],
222
- :set => Proc.new { |val| @directory = val }
223
- },
224
- {
225
- :tags => %w{ -H --with-filename },
226
- :set => Proc.new { @show_file_names = true }
227
- },
228
- {
229
- :tags => %w{ -h --no-filename },
230
- :set => Proc.new { @show_file_names = false }
231
- },
232
- {
233
- :tags => %w{ --label },
234
- :arg => [ :string ],
235
- :set => Proc.new { |val| @label = val }
236
- },
237
- {
238
- :tags => %w{ -m --match-limit },
239
- :arg => [ :integer ],
240
- :set => Proc.new { |val| @match_limit = val }
241
- },
242
- {
243
- :tags => %w{ -u --highlight },
244
- :arg => [ :optional, :regexp, %r{ ^ (?:(multi|single)|none) $ }x ],
245
- :set => Proc.new { |md| val = md ? md[1] : "multi"; set_highlight(val) }
246
- },
247
- {
248
- :tags => %w{ --basename --name --with-basename --with-name },
249
- :arg => [ :string ],
250
- :set => Proc.new { |pat| @with_basename = Regexp.create(pat) }
251
- },
252
- {
253
- :tags => %w{ --without-basename --without-name },
254
- :arg => [ :string ],
255
- :set => Proc.new { |pat| @without_basename = Regexp.create(pat) }
256
- },
257
- {
258
- :tags => %w{ --fullname --path --with-fullname --with-path },
259
- :arg => [ :string ],
260
- :set => Proc.new { |pat| @with_fullname = Regexp.create(pat) }
261
- },
262
- {
263
- :tags => %w{ --without-fullname --without-path },
264
- :arg => [ :string ],
265
- :set => Proc.new { |pat| @without_fullname = Regexp.create(pat) }
266
- },
267
- {
268
- :tags => %w{ --after },
269
- :arg => [ :required, :regexp, %r{ (\d+%?) $ }x ],
270
- :set => Proc.new { |md| @range_start = md[1] }
271
- },
272
- {
273
- :tags => %w{ --before },
274
- :arg => [ :required, :regexp, %r{ (\d+%?) $ }x ],
275
- :set => Proc.new { |md| @range_end = md[1] }
276
- },
277
- {
278
- :tags => %w{ -R --range },
279
- :arg => [ :required, :regexp, %r{ ^ (\d+%?),(\d+%?) $ }x ],
280
- :set => Proc.new do |md, opt, args|
281
- @range_start, @range_end = if md && md[1] && md[2]
282
- [ md[1], md[2] ]
283
- else
284
- [ args.shift, args.shift ]
285
- end
286
- end
287
- },
288
- {
289
- :tags => %w{ --binary-files },
290
- :arg => [ :required, :regexp, %r{ ^ [\'\"]? (text|without\-match|binary) [\'\"]? $ }x ],
291
- :set => Proc.new { |md| @binary_files = md[1] },
292
- :rc => %w{ binary-files },
293
- },
294
- {
295
- :tags => %w{ --size-limit },
296
- :arg => [ :integer ],
297
- :set => Proc.new { |val| @size_limit = val }
298
- },
299
- {
300
- :tags => %w{ -T --text-color },
301
- :arg => [ :string ],
302
- :set => Proc.new { |val| @text_highlights = [ make_highlight("text-color", val) ] }
303
- },
304
- # no longer supported:
305
- # {
306
- # :res => [ %r{ ^ --text-color- (\d+) (?:=(.+))? $ }x ],
307
- # :set => Proc.new do |md, opt, args|
308
- # idx = md[1].to_i
309
- # thl = md[2] || args.shift
310
- # @text_highlights[idx] = make_highlight(opt, thl)
311
- # end
312
- # },
313
- {
314
- :tags => %w{ -F --file-color },
315
- :arg => [ :string ],
316
- :set => Proc.new { |val| @file_highlight = make_highlight("file-color", val) }
317
- },
318
- {
319
- :tags => %w{ -f --file },
320
- :arg => [ :string ],
321
- :set => Proc.new { |fname| @expr = ExpressionFactory.new.read_file(fname) }
322
- },
323
- {
324
- :tags => %w{ -o -a },
325
- :set => Proc.new do |md, opt, args|
326
- args.unshift opt
327
- @expr = ExpressionFactory.new.make_expression(args)
328
- end
329
- },
330
- {
331
- :res => [ Regexp.new('^ -0 (\d{1,3})? $ ', Regexp::EXTENDED) ],
332
- :set => Proc.new { |md| rs = md ? md[1] : 0; set_record_separator(rs) }
333
- }
334
- ]
335
-
336
- @optset = OptProc::OptionSet.new(optdata)
337
-
338
- reset
339
- end
340
-
341
- def [](name)
342
- instance_eval("@" + name.to_s)
343
- end
344
-
345
- def reset
346
- @after = 0 # lines of context before the match
347
- @before = 0 # lines of context after the match
348
- @binary_files = "binary" #
349
- @count = false # just count the lines
350
- @directory = "read" # read, skip, or recurse, a la grep
351
- @expr = nil # the expression to be evaluated
352
- @exclude_matching = false # exclude files whose names match the expression
353
- @explain = false # display a legible version of the expression
354
- @extended = false # whether to use extended regular expressions
355
- @extract_matches = false # whether to show _only_ the part that matched
356
- @file_names_only = false # display only the file names
357
- @filter = true # display only matches
358
- @invert_match = false # display non-matching lines
359
- @nocase = false # match case
360
- @match_limit = nil # the maximum number of matches to display per file
361
- @multiline = false # whether to use multiline regexps
362
- @local_config_files = false # use local .glarkrc files
363
- @quiet = false # minimize warnings
364
- @range_end = nil # range to stop searching; nil => the entire file
365
- @range_start = nil # range to begin searching; nil => the entire file
366
- @show_line_numbers = true # display numbers of matching lines
367
- @show_file_names = nil # show the names of matching files; nil == > 1; true == >= 1; false means never
368
- @verbose = nil # display debugging output
369
- @whole_lines = false # true means patterns must match the entire line
370
- @whole_words = false # true means all patterns are '\b'ed front and back
371
- @write_null = false # in @file_names_only mode, write '\0' instead of '\n'
372
- @with_basename = nil # match files with this basename
373
- @without_basename = nil # match files without this basename
374
- @with_fullname = nil # match files with this fullname
375
- @without_fullname = nil # match files without this fullname
376
- @show_break = false # whether to show the break between sections
377
- @split_as_path = true # whether to split arguments that include the path separator
378
-
379
- @highlight = "multi" # highlight matches (using ANSI codes)
380
-
381
- @text_highlights = []
382
- @file_highlight = nil
383
- @line_number_highlight = nil
384
-
385
- @label = nil
386
- @size_limit = nil
387
- @out = $stdout
388
-
389
- $/ = "\n"
390
-
391
- set_output_style("ansi")
392
-
393
- reset_colors
394
- end
395
-
396
- def make_colors(limit = -1)
397
- Text::Highlighter::DEFAULT_COLORS[0 .. limit].collect { |color| @highlighter.make(color) }
398
- end
399
-
400
- def multi_colors
401
- make_colors
402
- end
403
-
404
- def single_color
405
- make_colors(0)
406
- end
407
-
408
- def highlight?(str)
409
- %w{ multi on true yes }.detect { |x| str == x }
410
- end
411
-
412
- def reset_colors
413
- if @highlight && @highlighter
414
- @text_highlights = case @highlight
415
- when highlight?(@highlight), true
416
- multi_colors
417
- when "single"
418
- single_color
419
- when "none", "off", "false", "no", nil, false
420
- []
421
- else
422
- warn "highlight format '" + @highlight.to_s + "' not recognized"
423
- single_color
424
- end
425
- @file_highlight = @highlighter.make("reverse bold")
426
- @line_number_highlight = nil
427
- else
428
- @text_highlights = []
429
- @file_highlight = nil
430
- @line_number_highlight = nil
431
- end
432
- end
433
-
434
- def set_highlight(type)
435
- @highlight = type
436
- reset_colors
437
- end
438
-
439
- def set_output_style(output)
440
- @output = output
441
-
442
- # log { sprintf("%s: %s\n", "text_highlights", @text_highlights.collect { |hl| hl.highlight("text") }.join(", ")) }
443
-
444
- @highlighter = case @output
445
- when "ansi", "xterm"
446
- Text::ANSIHighlighter
447
- when "grep"
448
- @highlight = false
449
- @show_line_numbers = false
450
- @after = 0
451
- @before = 0
452
- nil
453
- when "text", "match"
454
- @highlight = nil
455
- nil
456
- end
457
-
458
- reset_colors
459
- end
460
-
461
- def run(args)
462
- @args = args
463
-
464
- @exprfact = ExpressionFactory.new
465
-
466
- if hd = Env.home_directory
467
- hd = Pathname.new(hd)
468
- homerc = hd + ".glarkrc"
469
- read_rcfile(homerc)
470
- end
471
-
472
- if @local_config_files
473
- dir = Pathname.new(".").expand_path
474
- while !dir.root? && dir != hd
475
- rcfile = dir + ".glarkrc"
476
- if rcfile.exist?
477
- read_rcfile(rcfile)
478
- break
479
- else
480
- dir = dir.dirname
481
- end
482
- end
483
- end
484
-
485
- read_environment_variable
486
-
487
- # honor thy EMACS; go to grep mode
488
- if ENV["EMACS"]
489
- set_output_style("grep")
490
- end
491
-
492
- read_options
493
-
494
- validate
495
- end
496
-
497
- def set_record_separator(sep)
498
- log { "sep: #{sep}" }
499
- $/ = if sep && sep.to_i > 0
500
- begin
501
- sep.oct.chr
502
- rescue RangeError => e
503
- # out of range (e.g., 777) means nil:
504
- nil
505
- end
506
- else
507
- log { "setting to paragraph" }
508
- "\n\n"
509
- end
510
-
511
- log { "record separator set to #{$/.inspect}" }
512
- end
513
-
514
- def read_rcfile(rcfile)
515
- if rcfile.exist?
516
- rcfile.readlines.each do |line|
517
- line.sub!(/\s*#.*/, "")
518
- line.chomp!
519
- name, value = line.split(/\s*[=:]\s*/)
520
- next unless name && value
521
-
522
- # rc association is somewhat supported:
523
- @optset.options.each do |option|
524
- if option.match_rc?(name)
525
- val = option.convert_value(value)
526
- option.set(val)
527
- next
528
- end
529
- end
530
-
531
- case name
532
- when "expression"
533
- # this should be more intelligent than just splitting on whitespace:
534
- @expr = ExpressionFactory.new.make_expression(value.split(/\s+/))
535
- when "file-color"
536
- @file_highlight = make_highlight(name, value)
537
- when "filter"
538
- @filter = to_boolean(value)
539
- when "grep"
540
- set_output_style("grep") if to_boolean(value)
541
- when "highlight"
542
- @highlight = value
543
- when "ignore-case"
544
- @nocase = to_boolean(value)
545
- when "known-nontext-files"
546
- value.split.each do |ext|
547
- FileTester.set_nontext(ext)
548
- end
549
- when "known-text-files"
550
- value.split.each do |ext|
551
- FileTester.set_text(ext)
552
- end
553
- when "local-config-files"
554
- @local_config_files = to_boolean(value)
555
- when "line-number-color"
556
- @line_number_highlight = make_highlight(name, value)
557
- when "output"
558
- set_output_style(value)
559
- when "show-break"
560
- @show_break = to_boolean(value)
561
- when "quiet"
562
- Log.quiet = @quiet = to_boolean(value)
563
- when "text-color"
564
- @text_highlights = [ make_highlight(name, value) ]
565
- when %r{^text\-color\-(\d+)$}
566
- @text_highlights[$1.to_i] = make_highlight(name, value)
567
- when "verbose"
568
- Log.verbose = @verbose = to_boolean(value) ? 1 : nil
569
- when "verbosity"
570
- Log.verbose = @verbose = value.to_i
571
- when "split-as-path"
572
- @split_as_path = to_boolean(value)
573
- when "size-limit"
574
- @size_limit = value.to_i
575
- end
576
- end
577
- end
578
- end
579
-
580
- # creates a color for the given option, based on its value
581
- def make_highlight(opt, value)
582
- if hl = GlarkOptions.instance.highlighter
583
- if value
584
- hl.make(value)
585
- else
586
- error opt + " requires a color"
587
- exit 2
588
- end
589
- else
590
- log { "no highlighter defined" }
591
- end
592
- end
593
-
594
- # returns whether the value matches a true value, such as "yes", "true", or "on".
595
- def to_boolean(value)
596
- [ "yes", "true", "on" ].include?(value.downcase)
597
- end
598
-
599
- def read_environment_variable
600
- options = Env.split("GLARKOPTS")
601
- while options.size > 0
602
- @optset.process_option(options)
603
- end
604
- end
605
-
606
- def read_options
607
- nargs = @args.size
608
-
609
- # solitary "-v" means "--version", not --invert-match
610
- if nargs == 1 && @args[0] == "-v"
611
- show_version
612
- end
613
-
614
- @expr = nil
615
-
616
- while @args.size > 0 && @optset.process_option(@args)
617
- # nothing
618
- end
619
-
620
- if @expr
621
- # we already have an expression
622
- else
623
- if @args.size > 0
624
- known_end = false
625
- if @args[0] == "--"
626
- log { "end of options" }
627
- @args.shift
628
- known_end = true
629
- else
630
- # log { "not an option: #{@args[0]}" }
631
- end
632
-
633
- if @args && @args.size > 0
634
- @expr = ExpressionFactory.new.make_expression(@args, !known_end)
635
- end
636
- end
637
-
638
- unless @expr
639
- if nargs > 0
640
- error "No expression provided."
641
- end
642
-
643
- $stderr.puts "Usage: glark [options] expression file..."
644
- $stderr.puts "Try `glark --help' for more information."
645
- exit 1
646
- end
647
- end
648
- end
649
-
650
- def write_configuration
651
- fields = {
652
- "after-context" => @after,
653
- "before-context" => @before,
654
- "binary-files" => @binary_files,
655
- "file-color" => @file_highlight,
656
- "filter" => @filter,
657
- "highlight" => @highlight,
658
- "ignore-case" => @nocase,
659
- "known-nontext-files" => FileTester.nontext_extensions.sort.join(' '),
660
- "known-text-files" => FileTester.text_extensions.sort.join(' '),
661
- "line-number-color" => @line_number_highlight,
662
- "local-config-files" => @local_config_files,
663
- "output" => @output,
664
- "quiet" => @quiet,
665
- "show-break" => @show_break,
666
- "size-limit" => @size_limit,
667
- "split-as-path" => @split_as_path,
668
- "text-color" => @text_highlights.join(' '),
669
- "verbose" => @verbose,
670
- }
671
-
672
- fields.keys.sort.each do |fname|
673
- puts
674
- puts "#{fname}: #{fields[fname]}"
675
- end
676
- end
677
-
678
- def dump_all_fields
679
- fields = {
680
- "after" => @after,
681
- "before" => @before,
682
- "binary_files" => @binary_files,
683
- "count" => @count,
684
- "directory" => @directory,
685
- "exclude_matching" => @exclude_matching,
686
- "explain" => @explain,
687
- "expr" => @expr,
688
- "extract_matches" => @extract_matches,
689
- "file_highlight" => @file_highlight ? @file_highlight.highlight("filename") : "filename",
690
- "file_names_only" => @file_names_only,
691
- "filter" => @filter,
692
- "highlight" => @highlight,
693
- "invert_match" => @invert_match,
694
- "known_nontext_files" => FileTester.nontext_extensions.join(", "),
695
- "known_text_files" => FileTester.text_extensions.join(", "),
696
- "label" => @label,
697
- "line_number_highlight" => @line_number_highlight ? @line_number_highlight.highlight("12345") : "12345",
698
- "local_config_files" => @local_config_files,
699
- "match_limit" => @match_limit,
700
- "nocase" => @nocase,
701
- "output" => @output,
702
- "quiet" => @quiet,
703
- "range_end" => @range_end,
704
- "range_start" => @range_start,
705
- "ruby version" => RUBY_VERSION,
706
- "show_break" => @show_break,
707
- "show_file_names" => @show_file_names,
708
- "show_line_numbers" => @show_line_numbers,
709
- "text_highlights" => @text_highlights.compact.collect { |hl| hl.highlight("text") }.join(", "),
710
- "verbose" => @verbose,
711
- "version" => $VERSION,
712
- "whole_lines" => @whole_lines,
713
- "whole_words" => @whole_words,
714
- "with-basename" => @with_basename,
715
- "without-basename" => @without_basename,
716
- "with-fullname" => @with_fullname,
717
- "without-fullname" => @without_fullname,
718
- "write_null" => @write_null,
719
- }
720
-
721
- len = fields.keys.collect { |f| f.length }.max
722
-
723
- fields.keys.sort.each do |field|
724
- printf "%*s : %s\n", len, field, fields[field]
725
- end
726
- end
727
-
728
- # check options for collisions/data validity
729
- def validate
730
- if @range_start && @range_end
731
- pctre = Regexp.new('([\.\d]+)%')
732
- smd = pctre.match(@range_start)
733
- emd = pctre.match(@range_end)
734
-
735
- # both or neither are percentages:
736
- if !smd == !emd
737
- if smd
738
- if smd[1].to_f > emd[1].to_f
739
- error "range start (#{smd}) follows range end (#{emd})"
740
- exit 2
741
- end
742
- elsif @range_start.to_i > @range_end.to_i
743
- error "range start (#{@range_start}) follows range end (#{@range_end})"
744
- exit 2
745
- end
746
- end
747
- end
748
- end
749
-
750
- def show_version
751
- puts $PACKAGE + ", version " + $VERSION
752
- puts "Written by Jeff Pace (jpace@incava.org)."
753
- puts "Released under the Lesser GNU Public License."
754
- exit 0
755
- end
756
-
757
- end