]> Tony Duckles's Git Repositories (git.nynim.org) - dotfiles.git/blob - bin/ack
Initial commit
[dotfiles.git] / bin / ack
1 #!/usr/bin/env perl
2 #
3 # This file, ack, is generated code.
4 # Please DO NOT EDIT or send patches for it.
5 #
6 # Please take a look at the source from
7 # http://github.com/petdance/ack
8 # and submit patches against the individual files
9 # that build ack.
10 #
11
12 use warnings;
13 use strict;
14
15 our $VERSION = '1.92';
16 # Check http://betterthangrep.com/ for updates
17
18 # These are all our globals.
19
20
21 MAIN: {
22 if ( $App::Ack::VERSION ne $main::VERSION ) {
23 App::Ack::die( "Program/library version mismatch\n\t$0 is $main::VERSION\n\t$INC{'App/Ack.pm'} is $App::Ack::VERSION" );
24 }
25
26 # Do preliminary arg checking;
27 my $env_is_usable = 1;
28 for ( @ARGV ) {
29 last if ( $_ eq '--' );
30
31 # Priorities! Get the --thpppt checking out of the way.
32 /^--th[pt]+t+$/ && App::Ack::_thpppt($_);
33
34 # See if we want to ignore the environment. (Don't tell Al Gore.)
35 if ( $_ eq '--noenv' ) {
36 my @keys = ( 'ACKRC', grep { /^ACK_/ } keys %ENV );
37 delete @ENV{@keys};
38 $env_is_usable = 0;
39 }
40 }
41 unshift( @ARGV, App::Ack::read_ackrc() ) if $env_is_usable;
42 App::Ack::load_colors();
43
44 if ( exists $ENV{ACK_SWITCHES} ) {
45 App::Ack::warn( 'ACK_SWITCHES is no longer supported. Use ACK_OPTIONS.' );
46 }
47
48 if ( !@ARGV ) {
49 App::Ack::show_help();
50 exit 1;
51 }
52
53 main();
54 }
55
56 sub main {
57 my $opt = App::Ack::get_command_line_options();
58
59 $| = 1 if $opt->{flush}; # Unbuffer the output if flush mode
60
61 if ( App::Ack::input_from_pipe() ) {
62 # We're going into filter mode
63 for ( qw( f g l ) ) {
64 $opt->{$_} and App::Ack::die( "Can't use -$_ when acting as a filter." );
65 }
66 $opt->{show_filename} = 0;
67 $opt->{regex} = App::Ack::build_regex( defined $opt->{regex} ? $opt->{regex} : shift @ARGV, $opt );
68 if ( my $nargs = @ARGV ) {
69 my $s = $nargs == 1 ? '' : 's';
70 App::Ack::warn( "Ignoring $nargs argument$s on the command-line while acting as a filter." );
71 }
72 my $res = App::Ack::Resource::Basic->new( '-' );
73 App::Ack::search_resource( $res, $opt );
74 $res->close();
75 exit 0;
76 }
77
78 my $file_matching = $opt->{f} || $opt->{lines};
79 if ( !$file_matching ) {
80 @ARGV or App::Ack::die( 'No regular expression found.' );
81 $opt->{regex} = App::Ack::build_regex( defined $opt->{regex} ? $opt->{regex} : shift @ARGV, $opt );
82 }
83
84 # check that all regexes do compile fine
85 App::Ack::check_regex( $_ ) for ( $opt->{regex}, $opt->{G} );
86
87 my $what = App::Ack::get_starting_points( \@ARGV, $opt );
88 my $iter = App::Ack::get_iterator( $what, $opt );
89 App::Ack::filetype_setup();
90
91 my $nmatches = 0;
92
93 App::Ack::set_up_pager( $opt->{pager} ) if defined $opt->{pager};
94 if ( $opt->{f} ) {
95 $nmatches = App::Ack::print_files( $iter, $opt );
96 }
97 elsif ( $opt->{l} || $opt->{count} ) {
98 $nmatches = App::Ack::print_files_with_matches( $iter, $opt );
99 }
100 else {
101 $nmatches = App::Ack::print_matches( $iter, $opt );
102 }
103 close $App::Ack::fh;
104 exit ($nmatches ? 0 : 1);
105 }
106
107 =head1 NAME
108
109 ack - grep-like text finder
110
111 =head1 SYNOPSIS
112
113 ack [options] PATTERN [FILE...]
114 ack -f [options] [DIRECTORY...]
115
116 =head1 DESCRIPTION
117
118 Ack is designed as a replacement for 99% of the uses of F<grep>.
119
120 Ack searches the named input FILEs (or standard input if no files are
121 named, or the file name - is given) for lines containing a match to the
122 given PATTERN. By default, ack prints the matching lines.
123
124 Ack can also list files that would be searched, without actually searching
125 them, to let you take advantage of ack's file-type filtering capabilities.
126
127 =head1 FILE SELECTION
128
129 I<ack> is intelligent about the files it searches. It knows about
130 certain file types, based on both the extension on the file and,
131 in some cases, the contents of the file. These selections can be
132 made with the B<--type> option.
133
134 With no file selections, I<ack> only searches files of types that
135 it recognizes. If you have a file called F<foo.wango>, and I<ack>
136 doesn't know what a .wango file is, I<ack> won't search it.
137
138 The B<-a> option tells I<ack> to select all files, regardless of
139 type.
140
141 Some files will never be selected by I<ack>, even with B<-a>,
142 including:
143
144 =over 4
145
146 =item * Backup files: Files matching F<#*#> or ending with F<~>.
147
148 =item * Coredumps: Files matching F<core.\d+>
149
150 =back
151
152 However, I<ack> always searches the files given on the command line,
153 no matter what type. Furthermore, by specifying the B<-u> option all
154 files will be searched.
155
156 =head1 DIRECTORY SELECTION
157
158 I<ack> descends through the directory tree of the starting directories
159 specified. However, it will ignore the shadow directories used by
160 many version control systems, and the build directories used by the
161 Perl MakeMaker system. You may add or remove a directory from this
162 list with the B<--[no]ignore-dir> option. The option may be repeated
163 to add/remove multiple directories from the ignore list.
164
165 For a complete list of directories that do not get searched, run
166 F<ack --help>.
167
168 =head1 WHEN TO USE GREP
169
170 I<ack> trumps I<grep> as an everyday tool 99% of the time, but don't
171 throw I<grep> away, because there are times you'll still need it.
172
173 E.g., searching through huge files looking for regexes that can be
174 expressed with I<grep> syntax should be quicker with I<grep>.
175
176 If your script or parent program uses I<grep> C<--quiet> or
177 C<--silent> or needs exit 2 on IO error, use I<grep>.
178
179 =head1 OPTIONS
180
181 =over 4
182
183 =item B<-a>, B<--all>
184
185 Operate on all files, regardless of type (but still skip directories
186 like F<blib>, F<CVS>, etc.)
187
188 =item B<-A I<NUM>>, B<--after-context=I<NUM>>
189
190 Print I<NUM> lines of trailing context after matching lines.
191
192 =item B<-B I<NUM>>, B<--before-context=I<NUM>>
193
194 Print I<NUM> lines of leading context before matching lines.
195
196 =item B<-C [I<NUM>]>, B<--context[=I<NUM>]>
197
198 Print I<NUM> lines (default 2) of context around matching lines.
199
200 =item B<-c>, B<--count>
201
202 Suppress normal output; instead print a count of matching lines for
203 each input file. If B<-l> is in effect, it will only show the
204 number of lines for each file that has lines matching. Without
205 B<-l>, some line counts may be zeroes.
206
207 =item B<--color>, B<--nocolor>
208
209 B<--color> highlights the matching text. B<--nocolor> supresses
210 the color. This is on by default unless the output is redirected.
211
212 On Windows, this option is off by default unless the
213 L<Win32::Console::ANSI> module is installed or the C<ACK_PAGER_COLOR>
214 environment variable is used.
215
216 =item B<--color-filename=I<color>>
217
218 Sets the color to be used for filenames.
219
220 =item B<--color-match=I<color>>
221
222 Sets the color to be used for matches.
223
224 =item B<--column>
225
226 Show the column number of the first match. This is helpful for editors
227 that can place your cursor at a given position.
228
229 =item B<--env>, B<--noenv>
230
231 B<--noenv> disables all environment processing. No F<.ackrc> is read
232 and all environment variables are ignored. By default, F<ack> considers
233 F<.ackrc> and settings in the environment.
234
235 =item B<--flush>
236
237 B<--flush> flushes output immediately. This is off by default
238 unless ack is running interactively (when output goes to a pipe
239 or file).
240
241 =item B<-f>
242
243 Only print the files that would be searched, without actually doing
244 any searching. PATTERN must not be specified, or it will be taken as
245 a path to search.
246
247 =item B<--follow>, B<--nofollow>
248
249 Follow or don't follow symlinks, other than whatever starting files
250 or directories were specified on the command line.
251
252 This is off by default.
253
254 =item B<-G I<REGEX>>
255
256 Only paths matching I<REGEX> are included in the search. The entire
257 path and filename are matched against I<REGEX>, and I<REGEX> is a
258 Perl regular expression, not a shell glob.
259
260 The options B<-i>, B<-w>, B<-v>, and B<-Q> do not apply to this I<REGEX>.
261
262 =item B<-g I<REGEX>>
263
264 Print files where the relative path + filename matches I<REGEX>. This option is
265 a convenience shortcut for B<-f> B<-G I<REGEX>>.
266
267 The options B<-i>, B<-w>, B<-v>, and B<-Q> do not apply to this I<REGEX>.
268
269 =item B<--group>, B<--nogroup>
270
271 B<--group> groups matches by file name with. This is the default when
272 used interactively.
273
274 B<--nogroup> prints one result per line, like grep. This is the default
275 when output is redirected.
276
277 =item B<-H>, B<--with-filename>
278
279 Print the filename for each match.
280
281 =item B<-h>, B<--no-filename>
282
283 Suppress the prefixing of filenames on output when multiple files are
284 searched.
285
286 =item B<--help>
287
288 Print a short help statement.
289
290 =item B<-i>, B<--ignore-case>
291
292 Ignore case in the search strings.
293
294 This applies only to the PATTERN, not to the regexes given for the B<-g>
295 and B<-G> options.
296
297 =item B<--[no]ignore-dir=DIRNAME>
298
299 Ignore directory (as CVS, .svn, etc are ignored). May be used multiple times
300 to ignore multiple directories. For example, mason users may wish to include
301 B<--ignore-dir=data>. The B<--noignore-dir> option allows users to search
302 directories which would normally be ignored (perhaps to research the contents
303 of F<.svn/props> directories).
304
305 =item B<--line=I<NUM>>
306
307 Only print line I<NUM> of each file. Multiple lines can be given with multiple
308 B<--line> options or as a comma separated list (B<--line=3,5,7>). B<--line=4-7>
309 also works. The lines are always output in ascending order, no matter the
310 order given on the command line.
311
312 =item B<-l>, B<--files-with-matches>
313
314 Only print the filenames of matching files, instead of the matching text.
315
316 =item B<-L>, B<--files-without-matches>
317
318 Only print the filenames of files that do I<NOT> match. This is equivalent
319 to specifying B<-l> and B<-v>.
320
321 =item B<--match I<REGEX>>
322
323 Specify the I<REGEX> explicitly. This is helpful if you don't want to put the
324 regex as your first argument, e.g. when executing multiple searches over the
325 same set of files.
326
327 # search for foo and bar in given files
328 ack file1 t/file* --match foo
329 ack file1 t/file* --match bar
330
331 =item B<-m=I<NUM>>, B<--max-count=I<NUM>>
332
333 Stop reading a file after I<NUM> matches.
334
335 =item B<--man>
336
337 Print this manual page.
338
339 =item B<-n>
340
341 No descending into subdirectories.
342
343 =item B<-o>
344
345 Show only the part of each line matching PATTERN (turns off text
346 highlighting)
347
348 =item B<--output=I<expr>>
349
350 Output the evaluation of I<expr> for each line (turns off text
351 highlighting)
352
353 =item B<--pager=I<program>>
354
355 Direct ack's output through I<program>. This can also be specified
356 via the C<ACK_PAGER> and C<ACK_PAGER_COLOR> environment variables.
357
358 Using --pager does not suppress grouping and coloring like piping
359 output on the command-line does.
360
361 =item B<--passthru>
362
363 Prints all lines, whether or not they match the expression. Highlighting
364 will still work, though, so it can be used to highlight matches while
365 still seeing the entire file, as in:
366
367 # Watch a log file, and highlight a certain IP address
368 $ tail -f ~/access.log | ack --passthru 123.45.67.89
369
370 =item B<--print0>
371
372 Only works in conjunction with -f, -g, -l or -c (filename output). The filenames
373 are output separated with a null byte instead of the usual newline. This is
374 helpful when dealing with filenames that contain whitespace, e.g.
375
376 # remove all files of type html
377 ack -f --html --print0 | xargs -0 rm -f
378
379 =item B<-Q>, B<--literal>
380
381 Quote all metacharacters in PATTERN, it is treated as a literal.
382
383 This applies only to the PATTERN, not to the regexes given for the B<-g>
384 and B<-G> options.
385
386 =item B<--smart-case>, B<--no-smart-case>
387
388 Ignore case in the search strings if PATTERN contains no uppercase
389 characters. This is similar to C<smartcase> in vim. This option is
390 off by default.
391
392 B<-i> always overrides this option.
393
394 This applies only to the PATTERN, not to the regexes given for the
395 B<-g> and B<-G> options.
396
397 =item B<--sort-files>
398
399 Sorts the found files lexically. Use this if you want your file
400 listings to be deterministic between runs of I<ack>.
401
402 =item B<--thpppt>
403
404 Display the all-important Bill The Cat logo. Note that the exact
405 spelling of B<--thpppppt> is not important. It's checked against
406 a regular expression.
407
408 =item B<--type=TYPE>, B<--type=noTYPE>
409
410 Specify the types of files to include or exclude from a search.
411 TYPE is a filetype, like I<perl> or I<xml>. B<--type=perl> can
412 also be specified as B<--perl>, and B<--type=noperl> can be done
413 as B<--noperl>.
414
415 If a file is of both type "foo" and "bar", specifying --foo and
416 --nobar will exclude the file, because an exclusion takes precedence
417 over an inclusion.
418
419 Type specifications can be repeated and are ORed together.
420
421 See I<ack --help=types> for a list of valid types.
422
423 =item B<--type-add I<TYPE>=I<.EXTENSION>[,I<.EXT2>[,...]]>
424
425 Files with the given EXTENSION(s) are recognized as being of (the
426 existing) type TYPE. See also L</"Defining your own types">.
427
428
429 =item B<--type-set I<TYPE>=I<.EXTENSION>[,I<.EXT2>[,...]]>
430
431 Files with the given EXTENSION(s) are recognized as being of type
432 TYPE. This replaces an existing definition for type TYPE. See also
433 L</"Defining your own types">.
434
435 =item B<-u>, B<--unrestricted>
436
437 All files and directories (including blib/, core.*, ...) are searched,
438 nothing is skipped. When both B<-u> and B<--ignore-dir> are used, the
439 B<--ignore-dir> option has no effect.
440
441 =item B<-v>, B<--invert-match>
442
443 Invert match: select non-matching lines
444
445 This applies only to the PATTERN, not to the regexes given for the B<-g>
446 and B<-G> options.
447
448 =item B<--version>
449
450 Display version and copyright information.
451
452 =item B<-w>, B<--word-regexp>
453
454 Force PATTERN to match only whole words. The PATTERN is wrapped with
455 C<\b> metacharacters.
456
457 This applies only to the PATTERN, not to the regexes given for the B<-g>
458 and B<-G> options.
459
460 =item B<-1>
461
462 Stops after reporting first match of any kind. This is different
463 from B<--max-count=1> or B<-m1>, where only one match per file is
464 shown. Also, B<-1> works with B<-f> and B<-g>, where B<-m> does
465 not.
466
467 =back
468
469 =head1 THE .ackrc FILE
470
471 The F<.ackrc> file contains command-line options that are prepended
472 to the command line before processing. Multiple options may live
473 on multiple lines. Lines beginning with a # are ignored. A F<.ackrc>
474 might look like this:
475
476 # Always sort the files
477 --sort-files
478
479 # Always color, even if piping to a another program
480 --color
481
482 # Use "less -r" as my pager
483 --pager=less -r
484
485 Note that arguments with spaces in them do not need to be quoted,
486 as they are not interpreted by the shell. Basically, each I<line>
487 in the F<.ackrc> file is interpreted as one element of C<@ARGV>.
488
489 F<ack> looks in your home directory for the F<.ackrc>. You can
490 specify another location with the F<ACKRC> variable, below.
491
492 If B<--noenv> is specified on the command line, the F<.ackrc> file
493 is ignored.
494
495 =head1 Defining your own types
496
497 ack allows you to define your own types in addition to the predefined
498 types. This is done with command line options that are best put into
499 an F<.ackrc> file - then you do not have to define your types over and
500 over again. In the following examples the options will always be shown
501 on one command line so that they can be easily copy & pasted.
502
503 I<ack --perl foo> searches for foo in all perl files. I<ack --help=types>
504 tells you, that perl files are files ending
505 in .pl, .pm, .pod or .t. So what if you would like to include .xs
506 files as well when searching for --perl files? I<ack --type-add perl=.xs --perl foo>
507 does this for you. B<--type-add> appends
508 additional extensions to an existing type.
509
510 If you want to define a new type, or completely redefine an existing
511 type, then use B<--type-set>. I<ack --type-set
512 eiffel=.e,.eiffel> defines the type I<eiffel> to include files with
513 the extensions .e or .eiffel. So to search for all eiffel files
514 containing the word Bertrand use I<ack --type-set eiffel=.e,.eiffel --eiffel Bertrand>.
515 As usual, you can also write B<--type=eiffel>
516 instead of B<--eiffel>. Negation also works, so B<--noeiffel> excludes
517 all eiffel files from a search. Redefining also works: I<ack --type-set cc=.c,.h>
518 and I<.xs> files no longer belong to the type I<cc>.
519
520 When defining your own types in the F<.ackrc> file you have to use
521 the following:
522
523 --type-set=eiffel=.e,.eiffel
524
525 or writing on separate lines
526
527 --type-set
528 eiffel=.e,.eiffel
529
530 The following does B<NOT> work in the F<.ackrc> file:
531
532 --type-set eiffel=.e,.eiffel
533
534
535 In order to see all currently defined types, use I<--help types>, e.g.
536 I<ack --type-set backup=.bak --type-add perl=.perl --help types>
537
538 Restrictions:
539
540 =over 4
541
542 =item
543
544 The types 'skipped', 'make', 'binary' and 'text' are considered "builtin" and
545 cannot be altered.
546
547 =item
548
549 The shebang line recognition of the types 'perl', 'ruby', 'php', 'python',
550 'shell' and 'xml' cannot be redefined by I<--type-set>, it is always
551 active. However, the shebang line is only examined for files where the
552 extension is not recognised. Therefore it is possible to say
553 I<ack --type-set perl=.perl --type-set foo=.pl,.pm,.pod,.t --perl --nofoo> and
554 only find your shiny new I<.perl> files (and all files with unrecognized extension
555 and perl on the shebang line).
556
557 =back
558
559 =head1 ENVIRONMENT VARIABLES
560
561 For commonly-used ack options, environment variables can make life much easier.
562 These variables are ignored if B<--noenv> is specified on the command line.
563
564 =over 4
565
566 =item ACKRC
567
568 Specifies the location of the F<.ackrc> file. If this file doesn't
569 exist, F<ack> looks in the default location.
570
571 =item ACK_OPTIONS
572
573 This variable specifies default options to be placed in front of
574 any explicit options on the command line.
575
576 =item ACK_COLOR_FILENAME
577
578 Specifies the color of the filename when it's printed in B<--group>
579 mode. By default, it's "bold green".
580
581 The recognized attributes are clear, reset, dark, bold, underline,
582 underscore, blink, reverse, concealed black, red, green, yellow,
583 blue, magenta, on_black, on_red, on_green, on_yellow, on_blue,
584 on_magenta, on_cyan, and on_white. Case is not significant.
585 Underline and underscore are equivalent, as are clear and reset.
586 The color alone sets the foreground color, and on_color sets the
587 background color.
588
589 This option can also be set with B<--color-filename>.
590
591 =item ACK_COLOR_MATCH
592
593 Specifies the color of the matching text when printed in B<--color>
594 mode. By default, it's "black on_yellow".
595
596 This option can also be set with B<--color-match>.
597
598 See B<ACK_COLOR_FILENAME> for the color specifications.
599
600 =item ACK_PAGER
601
602 Specifies a pager program, such as C<more>, C<less> or C<most>, to which
603 ack will send its output.
604
605 Using C<ACK_PAGER> does not suppress grouping and coloring like
606 piping output on the command-line does, except that on Windows
607 ack will assume that C<ACK_PAGER> does not support color.
608
609 C<ACK_PAGER_COLOR> overrides C<ACK_PAGER> if both are specified.
610
611 =item ACK_PAGER_COLOR
612
613 Specifies a pager program that understands ANSI color sequences.
614 Using C<ACK_PAGER_COLOR> does not suppress grouping and coloring
615 like piping output on the command-line does.
616
617 If you are not on Windows, you never need to use C<ACK_PAGER_COLOR>.
618
619 =back
620
621 =head1 ACK & OTHER TOOLS
622
623 =head2 Vim integration
624
625 F<ack> integrates easily with the Vim text editor. Set this in your
626 F<.vimrc> to use F<ack> instead of F<grep>:
627
628 set grepprg=ack\ -a
629
630 That examples uses C<-a> to search through all files, but you may
631 use other default flags. Now you can search with F<ack> and easily
632 step through the results in Vim:
633
634 :grep Dumper perllib
635
636 =head2 Emacs integration
637
638 Phil Jackson put together an F<ack.el> extension that "provides a
639 simple compilation mode ... has the ability to guess what files you
640 want to search for based on the major-mode."
641
642 L<http://www.shellarchive.co.uk/content/emacs.html>
643
644 =head2 TextMate integration
645
646 Pedro Melo is a TextMate user who writes "I spend my day mostly
647 inside TextMate, and the built-in find-in-project sucks with large
648 projects. So I hacked a TextMate command that was using find +
649 grep to use ack. The result is the Search in Project with ack, and
650 you can find it here:
651 L<http://www.simplicidade.org/notes/archives/2008/03/search_in_proje.html>"
652
653 =head2 Shell and Return Code
654
655 For greater compatibility with I<grep>, I<ack> in normal use returns
656 shell return or exit code of 0 only if something is found and 1 if
657 no match is found.
658
659 (Shell exit code 1 is C<$?=256> in perl with C<system> or backticks.)
660
661 The I<grep> code 2 for errors is not used.
662
663 If C<-f> or C<-g> are specified, then 0 is returned if at least one
664 file is found. If no files are found, then 1 is returned.
665
666 =cut
667
668 =head1 DEBUGGING ACK PROBLEMS
669
670 If ack gives you output you're not expecting, start with a few simple steps.
671
672 =head2 Use B<--noenv>
673
674 Your environment variables and F<.ackrc> may be doing things you're
675 not expecting, or forgotten you specified. Use B<--noenv> to ignore
676 your environment and F<.ackrc>.
677
678 =head2 Use B<-f> to see what files you're scanning
679
680 The reason I created B<-f> in the first place was as a debugging
681 tool. If ack is not finding matches you think it should find, run
682 F<ack -f> to see what files are being checked.
683
684 =head1 TIPS
685
686 =head2 Use the F<.ackrc> file.
687
688 The F<.ackrc> is the place to put all your options you use most of
689 the time but don't want to remember. Put all your --type-add and
690 --type-set definitions in it. If you like --smart-case, set it
691 there, too. I also set --sort-files there.
692
693 =head2 Use F<-f> for working with big codesets
694
695 Ack does more than search files. C<ack -f --perl> will create a
696 list of all the Perl files in a tree, ideal for sending into F<xargs>.
697 For example:
698
699 # Change all "this" to "that" in all Perl files in a tree.
700 ack -f --perl | xargs perl -p -i -e's/this/that/g'
701
702 or if you prefer:
703
704 perl -p -i -e's/this/thatg/' $(ack -f --perl)
705
706 =head2 Use F<-Q> when in doubt about metacharacters
707
708 If you're searching for something with a regular expression
709 metacharacter, most often a period in a filename or IP address, add
710 the -Q to avoid false positives without all the backslashing. See
711 the following example for more...
712
713 =head2 Use ack to watch log files
714
715 Here's one I used the other day to find trouble spots for a website
716 visitor. The user had a problem loading F<troublesome.gif>, so I
717 took the access log and scanned it with ack twice.
718
719 ack -Q aa.bb.cc.dd /path/to/access.log | ack -Q -B5 troublesome.gif
720
721 The first ack finds only the lines in the Apache log for the given
722 IP. The second finds the match on my troublesome GIF, and shows
723 the previous five lines from the log in each case.
724
725 =head2 Share your knowledge
726
727 Join the ack-users mailing list. Send me your tips and I may add
728 them here.
729
730 =head1 FAQ
731
732 =head2 Why isn't ack finding a match in (some file)?
733
734 Probably because it's of a type that ack doesn't recognize.
735
736 ack's searching behavior is driven by filetype. If ack doesn't
737 know what kind of file it is, ack ignores it.
738
739 If you want ack to search files that it doesn't recognize, use the
740 C<-a> switch.
741
742 If you want ack to search every file, even ones that it always
743 ignores like coredumps and backup files, use the C<-u> switch.
744
745 =head2 Why does ack ignore unknown files by default?
746
747 ack is designed by a programmer, for programmers, for searching
748 large trees of code. Most codebases have a lot files in them which
749 aren't source files (like compiled object files, source control
750 metadata, etc), and grep wastes a lot of time searching through all
751 of those as well and returning matches from those files.
752
753 That's why ack's behavior of not searching things it doesn't recognize
754 is one of its greatest strengths: the speed you get from only
755 searching the things that you want to be looking at.
756
757 =head2 Wouldn't it be great if F<ack> did search & replace?
758
759 No, ack will always be read-only. Perl has a perfectly good way
760 to do search & replace in files, using the C<-i>, C<-p> and C<-n>
761 switches.
762
763 You can certainly use ack to select your files to update. For
764 example, to change all "foo" to "bar" in all PHP files, you can do
765 this form the Unix shell:
766
767 $ perl -i -p -e's/foo/bar/g' $(ack -f --php)
768
769 =head2 Can you make ack recognize F<.xyz> files?
770
771 That's an enhancement. Please see the section in the manual about
772 enhancements.
773
774 =head2 There's already a program/package called ack.
775
776 Yes, I know.
777
778 =head2 Why is it called ack if it's called ack-grep?
779
780 The name of the program is "ack". Some packagers have called it
781 "ack-grep" when creating packages because there's already a package
782 out there called "ack" that has nothing to do with this ack.
783
784 I suggest you rename your ack-grep install to "ack" because one of
785 the crucial benefits of ack is having a name that's so short and
786 simple to type.
787
788 =head1 AUTHOR
789
790 Andy Lester, C<< <andy at petdance.com> >>
791
792 =head1 BUGS
793
794 Please report any bugs or feature requests to the issues list at
795 Github: L<http://github.com/petdance/ack/issues>
796
797 =head1 ENHANCEMENTS
798
799 All enhancement requests MUST first be posted to the ack-users
800 mailing list at L<http://groups.google.com/group/ack-users>. I
801 will not consider a request without it first getting seen by other
802 ack users. This includes requests for new filetypes.
803
804 There is a list of enhancements I want to make to F<ack> in the ack
805 issues list at Github: L<http://github.com/petdance/ack/issues>
806
807 Patches are always welcome, but patches with tests get the most
808 attention.
809
810 =head1 SUPPORT
811
812 Support for and information about F<ack> can be found at:
813
814 =over 4
815
816 =item * The ack homepage
817
818 L<http://betterthangrep.com/>
819
820 =item * The ack issues list at Github
821
822 L<http://github.com/petdance/ack/issues>
823
824 =item * AnnoCPAN: Annotated CPAN documentation
825
826 L<http://annocpan.org/dist/ack>
827
828 =item * CPAN Ratings
829
830 L<http://cpanratings.perl.org/d/ack>
831
832 =item * Search CPAN
833
834 L<http://search.cpan.org/dist/ack>
835
836 =item * Git source repository
837
838 L<http://github.com/petdance/ack>
839
840 =back
841
842 =head1 ACKNOWLEDGEMENTS
843
844 How appropriate to have I<ack>nowledgements!
845
846 Thanks to everyone who has contributed to ack in any way, including
847 Packy Anderson,
848 JR Boyens,
849 Dan Sully,
850 Ryan Niebur,
851 Kent Fredric,
852 Mike Morearty,
853 Ingmar Vanhassel,
854 Eric Van Dewoestine,
855 Sitaram Chamarty,
856 Adam James,
857 Richard Carlsson,
858 Pedro Melo,
859 AJ Schuster,
860 Phil Jackson,
861 Michael Schwern,
862 Jan Dubois,
863 Christopher J. Madsen,
864 Matthew Wickline,
865 David Dyck,
866 Jason Porritt,
867 Jjgod Jiang,
868 Thomas Klausner,
869 Uri Guttman,
870 Peter Lewis,
871 Kevin Riggle,
872 Ori Avtalion,
873 Torsten Blix,
874 Nigel Metheringham,
875 GE<aacute>bor SzabE<oacute>,
876 Tod Hagan,
877 Michael Hendricks,
878 E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason,
879 Piers Cawley,
880 Stephen Steneker,
881 Elias Lutfallah,
882 Mark Leighton Fisher,
883 Matt Diephouse,
884 Christian Jaeger,
885 Bill Sully,
886 Bill Ricker,
887 David Golden,
888 Nilson Santos F. Jr,
889 Elliot Shank,
890 Merijn Broeren,
891 Uwe Voelker,
892 Rick Scott,
893 Ask BjE<oslash>rn Hansen,
894 Jerry Gay,
895 Will Coleda,
896 Mike O'Regan,
897 Slaven ReziE<0x107>,
898 Mark Stosberg,
899 David Alan Pisoni,
900 Adriano Ferreira,
901 James Keenan,
902 Leland Johnson,
903 Ricardo Signes
904 and Pete Krawczyk.
905
906 =head1 COPYRIGHT & LICENSE
907
908 Copyright 2005-2009 Andy Lester.
909
910 This program is free software; you can redistribute it and/or modify
911 it under the terms of either:
912
913 =over 4
914
915 =item * the GNU General Public License as published by the Free
916 Software Foundation; either version 1, or (at your option) any later
917 version, or
918
919 =item * the Artistic License version 2.0.
920
921 =back
922
923 =cut
924 package File::Next;
925
926 use strict;
927 use warnings;
928
929
930 our $VERSION = '1.06';
931
932
933
934 use File::Spec ();
935
936
937 our $name; # name of the current file
938 our $dir; # dir of the current file
939
940 our %files_defaults;
941 our %skip_dirs;
942
943 BEGIN {
944 %files_defaults = (
945 file_filter => undef,
946 descend_filter => undef,
947 error_handler => sub { CORE::die @_ },
948 sort_files => undef,
949 follow_symlinks => 1,
950 );
951 %skip_dirs = map {($_,1)} (File::Spec->curdir, File::Spec->updir);
952 }
953
954
955 sub files {
956 ($_[0] eq __PACKAGE__) && die 'File::Next::files must not be invoked as File::Next->files';
957
958 my ($parms,@queue) = _setup( \%files_defaults, @_ );
959 my $filter = $parms->{file_filter};
960
961 return sub {
962 while (@queue) {
963 my ($dir,$file,$fullpath) = splice( @queue, 0, 3 );
964 if ( -f $fullpath ) {
965 if ( $filter ) {
966 local $_ = $file;
967 local $File::Next::dir = $dir;
968 local $File::Next::name = $fullpath;
969 next if not $filter->();
970 }
971 return wantarray ? ($dir,$file,$fullpath) : $fullpath;
972 }
973 elsif ( -d _ ) {
974 unshift( @queue, _candidate_files( $parms, $fullpath ) );
975 }
976 } # while
977
978 return;
979 }; # iterator
980 }
981
982
983
984
985
986
987
988 sub sort_standard($$) { return $_[0]->[1] cmp $_[1]->[1] }
989 sub sort_reverse($$) { return $_[1]->[1] cmp $_[0]->[1] }
990
991 sub reslash {
992 my $path = shift;
993
994 my @parts = split( /\//, $path );
995
996 return $path if @parts < 2;
997
998 return File::Spec->catfile( @parts );
999 }
1000
1001
1002
1003 sub _setup {
1004 my $defaults = shift;
1005 my $passed_parms = ref $_[0] eq 'HASH' ? {%{+shift}} : {}; # copy parm hash
1006
1007 my %passed_parms = %{$passed_parms};
1008
1009 my $parms = {};
1010 for my $key ( keys %{$defaults} ) {
1011 $parms->{$key} =
1012 exists $passed_parms{$key}
1013 ? delete $passed_parms{$key}
1014 : $defaults->{$key};
1015 }
1016
1017 # Any leftover keys are bogus
1018 for my $badkey ( keys %passed_parms ) {
1019 my $sub = (caller(1))[3];
1020 $parms->{error_handler}->( "Invalid option passed to $sub(): $badkey" );
1021 }
1022
1023 # If it's not a code ref, assume standard sort
1024 if ( $parms->{sort_files} && ( ref($parms->{sort_files}) ne 'CODE' ) ) {
1025 $parms->{sort_files} = \&sort_standard;
1026 }
1027 my @queue;
1028
1029 for ( @_ ) {
1030 my $start = reslash( $_ );
1031 if (-d $start) {
1032 push @queue, ($start,undef,$start);
1033 }
1034 else {
1035 push @queue, (undef,$start,$start);
1036 }
1037 }
1038
1039 return ($parms,@queue);
1040 }
1041
1042
1043 sub _candidate_files {
1044 my $parms = shift;
1045 my $dir = shift;
1046
1047 my $dh;
1048 if ( !opendir $dh, $dir ) {
1049 $parms->{error_handler}->( "$dir: $!" );
1050 return;
1051 }
1052
1053 my @newfiles;
1054 my $descend_filter = $parms->{descend_filter};
1055 my $follow_symlinks = $parms->{follow_symlinks};
1056 my $sort_sub = $parms->{sort_files};
1057
1058 for my $file ( grep { !exists $skip_dirs{$_} } readdir $dh ) {
1059 my $has_stat;
1060
1061 # Only do directory checking if we have a descend_filter
1062 my $fullpath = File::Spec->catdir( $dir, $file );
1063 if ( !$follow_symlinks ) {
1064 next if -l $fullpath;
1065 $has_stat = 1;
1066 }
1067
1068 if ( $descend_filter ) {
1069 if ( $has_stat ? (-d _) : (-d $fullpath) ) {
1070 local $File::Next::dir = $fullpath;
1071 local $_ = $file;
1072 next if not $descend_filter->();
1073 }
1074 }
1075 if ( $sort_sub ) {
1076 push( @newfiles, [ $dir, $file, $fullpath ] );
1077 }
1078 else {
1079 push( @newfiles, $dir, $file, $fullpath );
1080 }
1081 }
1082 closedir $dh;
1083
1084 if ( $sort_sub ) {
1085 return map { @{$_} } sort $sort_sub @newfiles;
1086 }
1087
1088 return @newfiles;
1089 }
1090
1091
1092 1; # End of File::Next
1093 package App::Ack;
1094
1095 use warnings;
1096 use strict;
1097
1098
1099
1100
1101 our $VERSION;
1102 our $COPYRIGHT;
1103 BEGIN {
1104 $VERSION = '1.92';
1105 $COPYRIGHT = 'Copyright 2005-2009 Andy Lester.';
1106 }
1107
1108 our $fh;
1109
1110 BEGIN {
1111 $fh = *STDOUT;
1112 }
1113
1114
1115 our %types;
1116 our %type_wanted;
1117 our %mappings;
1118 our %ignore_dirs;
1119
1120 our $input_from_pipe;
1121 our $output_to_pipe;
1122
1123 our $dir_sep_chars;
1124 our $is_cygwin;
1125 our $is_windows;
1126
1127 use File::Spec ();
1128 use File::Glob ':glob';
1129 use Getopt::Long ();
1130
1131 BEGIN {
1132 %ignore_dirs = (
1133 '.bzr' => 'Bazaar',
1134 '.cdv' => 'Codeville',
1135 '~.dep' => 'Interface Builder',
1136 '~.dot' => 'Interface Builder',
1137 '~.nib' => 'Interface Builder',
1138 '~.plst' => 'Interface Builder',
1139 '.git' => 'Git',
1140 '.hg' => 'Mercurial',
1141 '.pc' => 'quilt',
1142 '.svn' => 'Subversion',
1143 blib => 'Perl module building',
1144 CVS => 'CVS',
1145 RCS => 'RCS',
1146 SCCS => 'SCCS',
1147 _darcs => 'darcs',
1148 _sgbak => 'Vault/Fortress',
1149 'autom4te.cache' => 'autoconf',
1150 'cover_db' => 'Devel::Cover',
1151 _build => 'Module::Build',
1152 );
1153
1154 %mappings = (
1155 actionscript => [qw( as mxml )],
1156 ada => [qw( ada adb ads )],
1157 asm => [qw( asm s )],
1158 batch => [qw( bat cmd )],
1159 binary => q{Binary files, as defined by Perl's -B op (default: off)},
1160 cc => [qw( c h xs )],
1161 cfmx => [qw( cfc cfm cfml )],
1162 cpp => [qw( cpp cc cxx m hpp hh h hxx )],
1163 csharp => [qw( cs )],
1164 css => [qw( css )],
1165 elisp => [qw( el )],
1166 erlang => [qw( erl hrl )],
1167 fortran => [qw( f f77 f90 f95 f03 for ftn fpp )],
1168 haskell => [qw( hs lhs )],
1169 hh => [qw( h )],
1170 html => [qw( htm html shtml xhtml )],
1171 java => [qw( java properties )],
1172 js => [qw( js )],
1173 jsp => [qw( jsp jspx jhtm jhtml )],
1174 lisp => [qw( lisp lsp )],
1175 lua => [qw( lua )],
1176 make => q{Makefiles},
1177 mason => [qw( mas mhtml mpl mtxt )],
1178 objc => [qw( m h )],
1179 objcpp => [qw( mm h )],
1180 ocaml => [qw( ml mli )],
1181 parrot => [qw( pir pasm pmc ops pod pg tg )],
1182 perl => [qw( pl pm pod t )],
1183 php => [qw( php phpt php3 php4 php5 phtml)],
1184 plone => [qw( pt cpt metadata cpy py )],
1185 python => [qw( py )],
1186 rake => q{Rakefiles},
1187 ruby => [qw( rb rhtml rjs rxml erb rake )],
1188 scala => [qw( scala )],
1189 scheme => [qw( scm ss )],
1190 shell => [qw( sh bash csh tcsh ksh zsh )],
1191 skipped => q{Files, but not directories, normally skipped by ack (default: off)},
1192 smalltalk => [qw( st )],
1193 sql => [qw( sql ctl )],
1194 tcl => [qw( tcl itcl itk )],
1195 tex => [qw( tex cls sty )],
1196 text => q{Text files, as defined by Perl's -T op (default: off)},
1197 tt => [qw( tt tt2 ttml )],
1198 vb => [qw( bas cls frm ctl vb resx )],
1199 vim => [qw( vim )],
1200 yaml => [qw( yaml yml )],
1201 xml => [qw( xml dtd xslt ent )],
1202 );
1203
1204 while ( my ($type,$exts) = each %mappings ) {
1205 if ( ref $exts ) {
1206 for my $ext ( @{$exts} ) {
1207 push( @{$types{$ext}}, $type );
1208 }
1209 }
1210 }
1211
1212 # These have to be checked before any filehandle diddling.
1213 $output_to_pipe = not -t *STDOUT;
1214 $input_from_pipe = -p STDIN;
1215
1216 $is_cygwin = ($^O eq 'cygwin');
1217 $is_windows = ($^O =~ /MSWin32/);
1218 $dir_sep_chars = $is_windows ? quotemeta( '\\/' ) : quotemeta( File::Spec->catfile( '', '' ) );
1219 }
1220
1221
1222 sub read_ackrc {
1223 my @files = ( $ENV{ACKRC} );
1224 my @dirs =
1225 $is_windows
1226 ? ( $ENV{HOME}, $ENV{USERPROFILE} )
1227 : ( '~', $ENV{HOME} );
1228 for my $dir ( grep { defined } @dirs ) {
1229 for my $file ( '.ackrc', '_ackrc' ) {
1230 push( @files, bsd_glob( "$dir/$file", GLOB_TILDE ) );
1231 }
1232 }
1233 for my $filename ( @files ) {
1234 if ( defined $filename && -e $filename ) {
1235 open( my $fh, '<', $filename ) or App::Ack::die( "$filename: $!\n" );
1236 my @lines = grep { /./ && !/^\s*#/ } <$fh>;
1237 chomp @lines;
1238 close $fh or App::Ack::die( "$filename: $!\n" );
1239
1240 return @lines;
1241 }
1242 }
1243
1244 return;
1245 }
1246
1247
1248 sub get_command_line_options {
1249 my %opt = (
1250 pager => $ENV{ACK_PAGER_COLOR} || $ENV{ACK_PAGER},
1251 );
1252
1253 my $getopt_specs = {
1254 1 => sub { $opt{1} = $opt{m} = 1 },
1255 'A|after-context=i' => \$opt{after_context},
1256 'B|before-context=i' => \$opt{before_context},
1257 'C|context:i' => sub { shift; my $val = shift; $opt{before_context} = $opt{after_context} = ($val || 2) },
1258 'a|all-types' => \$opt{all},
1259 'break!' => \$opt{break},
1260 c => \$opt{count},
1261 'color|colour!' => \$opt{color},
1262 'color-match=s' => \$ENV{ACK_COLOR_MATCH},
1263 'color-filename=s' => \$ENV{ACK_COLOR_FILENAME},
1264 'column!' => \$opt{column},
1265 count => \$opt{count},
1266 'env!' => sub { }, # ignore this option, it is handled beforehand
1267 f => \$opt{f},
1268 flush => \$opt{flush},
1269 'follow!' => \$opt{follow},
1270 'g=s' => sub { shift; $opt{G} = shift; $opt{f} = 1 },
1271 'G=s' => \$opt{G},
1272 'group!' => sub { shift; $opt{heading} = $opt{break} = shift },
1273 'heading!' => \$opt{heading},
1274 'h|no-filename' => \$opt{h},
1275 'H|with-filename' => \$opt{H},
1276 'i|ignore-case' => \$opt{i},
1277 'lines=s' => sub { shift; my $val = shift; push @{$opt{lines}}, $val },
1278 'l|files-with-matches' => \$opt{l},
1279 'L|files-without-matches' => sub { $opt{l} = $opt{v} = 1 },
1280 'm|max-count=i' => \$opt{m},
1281 'match=s' => \$opt{regex},
1282 'n|no-recurse' => \$opt{n},
1283 o => sub { $opt{output} = '$&' },
1284 'output=s' => \$opt{output},
1285 'pager=s' => \$opt{pager},
1286 'nopager' => sub { $opt{pager} = undef },
1287 'passthru' => \$opt{passthru},
1288 'print0' => \$opt{print0},
1289 'Q|literal' => \$opt{Q},
1290 'r|R|recurse' => sub {},
1291 'smart-case!' => \$opt{smart_case},
1292 'sort-files' => \$opt{sort_files},
1293 'u|unrestricted' => \$opt{u},
1294 'v|invert-match' => \$opt{v},
1295 'w|word-regexp' => \$opt{w},
1296
1297 'ignore-dirs=s' => sub { shift; my $dir = remove_dir_sep( shift ); $ignore_dirs{$dir} = '--ignore-dirs' },
1298 'noignore-dirs=s' => sub { shift; my $dir = remove_dir_sep( shift ); delete $ignore_dirs{$dir} },
1299
1300 'version' => sub { print_version_statement(); exit 1; },
1301 'help|?:s' => sub { shift; show_help(@_); exit; },
1302 'help-types'=> sub { show_help_types(); exit; },
1303 'man' => sub { require Pod::Usage; Pod::Usage::pod2usage({-verbose => 2}); exit; },
1304
1305 'type=s' => sub {
1306 # Whatever --type=xxx they specify, set it manually in the hash
1307 my $dummy = shift;
1308 my $type = shift;
1309 my $wanted = ($type =~ s/^no//) ? 0 : 1; # must not be undef later
1310
1311 if ( exists $type_wanted{ $type } ) {
1312 $type_wanted{ $type } = $wanted;
1313 }
1314 else {
1315 App::Ack::die( qq{Unknown --type "$type"} );
1316 }
1317 }, # type sub
1318 };
1319
1320 # Stick any default switches at the beginning, so they can be overridden
1321 # by the command line switches.
1322 unshift @ARGV, split( ' ', $ENV{ACK_OPTIONS} ) if defined $ENV{ACK_OPTIONS};
1323
1324 # first pass through options, looking for type definitions
1325 def_types_from_ARGV();
1326
1327 for my $i ( filetypes_supported() ) {
1328 $getopt_specs->{ "$i!" } = \$type_wanted{ $i };
1329 }
1330
1331
1332 my $parser = Getopt::Long::Parser->new();
1333 $parser->configure( 'bundling', 'no_ignore_case', );
1334 $parser->getoptions( %{$getopt_specs} ) or
1335 App::Ack::die( 'See ack --help, ack --help-types or ack --man for options.' );
1336
1337 my $to_screen = not output_to_pipe();
1338 my %defaults = (
1339 all => 0,
1340 color => $to_screen,
1341 follow => 0,
1342 break => $to_screen,
1343 heading => $to_screen,
1344 before_context => 0,
1345 after_context => 0,
1346 );
1347 if ( $is_windows && $defaults{color} && not $ENV{ACK_PAGER_COLOR} ) {
1348 if ( $ENV{ACK_PAGER} || not eval { require Win32::Console::ANSI } ) {
1349 $defaults{color} = 0;
1350 }
1351 }
1352 if ( $to_screen && $ENV{ACK_PAGER_COLOR} ) {
1353 $defaults{color} = 1;
1354 }
1355
1356 while ( my ($key,$value) = each %defaults ) {
1357 if ( not defined $opt{$key} ) {
1358 $opt{$key} = $value;
1359 }
1360 }
1361
1362 if ( defined $opt{m} && $opt{m} <= 0 ) {
1363 App::Ack::die( '-m must be greater than zero' );
1364 }
1365
1366 for ( qw( before_context after_context ) ) {
1367 if ( defined $opt{$_} && $opt{$_} < 0 ) {
1368 App::Ack::die( "--$_ may not be negative" );
1369 }
1370 }
1371
1372 if ( defined( my $val = $opt{output} ) ) {
1373 $opt{output} = eval qq[ sub { "$val" } ];
1374 }
1375 if ( defined( my $l = $opt{lines} ) ) {
1376 # --line=1 --line=5 is equivalent to --line=1,5
1377 my @lines = split( /,/, join( ',', @{$l} ) );
1378
1379 # --line=1-3 is equivalent to --line=1,2,3
1380 @lines = map {
1381 my @ret;
1382 if ( /-/ ) {
1383 my ($from, $to) = split /-/, $_;
1384 if ( $from > $to ) {
1385 App::Ack::warn( "ignoring --line=$from-$to" );
1386 @ret = ();
1387 }
1388 else {
1389 @ret = ( $from .. $to );
1390 }
1391 }
1392 else {
1393 @ret = ( $_ );
1394 };
1395 @ret
1396 } @lines;
1397
1398 if ( @lines ) {
1399 my %uniq;
1400 @uniq{ @lines } = ();
1401 $opt{lines} = [ sort { $a <=> $b } keys %uniq ]; # numerical sort and each line occurs only once!
1402 }
1403 else {
1404 # happens if there are only ignored --line directives
1405 App::Ack::die( 'All --line options are invalid.' );
1406 }
1407 }
1408
1409 return \%opt;
1410 }
1411
1412
1413 sub def_types_from_ARGV {
1414 my @typedef;
1415
1416 my $parser = Getopt::Long::Parser->new();
1417 # pass_through => leave unrecognized command line arguments alone
1418 # no_auto_abbrev => otherwise -c is expanded and not left alone
1419 $parser->configure( 'no_ignore_case', 'pass_through', 'no_auto_abbrev' );
1420 $parser->getoptions(
1421 'type-set=s' => sub { shift; push @typedef, ['c', shift] },
1422 'type-add=s' => sub { shift; push @typedef, ['a', shift] },
1423 ) or App::Ack::die( 'See ack --help or ack --man for options.' );
1424
1425 for my $td (@typedef) {
1426 my ($type, $ext) = split /=/, $td->[1];
1427
1428 if ( $td->[0] eq 'c' ) {
1429 # type-set
1430 if ( exists $mappings{$type} ) {
1431 # can't redefine types 'make', 'skipped', 'text' and 'binary'
1432 App::Ack::die( qq{--type-set: Builtin type "$type" cannot be changed.} )
1433 if ref $mappings{$type} ne 'ARRAY';
1434
1435 delete_type($type);
1436 }
1437 }
1438 else {
1439 # type-add
1440
1441 # can't append to types 'make', 'skipped', 'text' and 'binary'
1442 App::Ack::die( qq{--type-add: Builtin type "$type" cannot be changed.} )
1443 if exists $mappings{$type} && ref $mappings{$type} ne 'ARRAY';
1444
1445 App::Ack::warn( qq{--type-add: Type "$type" does not exist, creating with "$ext" ...} )
1446 unless exists $mappings{$type};
1447 }
1448
1449 my @exts = split /,/, $ext;
1450 s/^\.// for @exts;
1451
1452 if ( !exists $mappings{$type} || ref($mappings{$type}) eq 'ARRAY' ) {
1453 push @{$mappings{$type}}, @exts;
1454 for my $e ( @exts ) {
1455 push @{$types{$e}}, $type;
1456 }
1457 }
1458 else {
1459 App::Ack::die( qq{Cannot append to type "$type".} );
1460 }
1461 }
1462
1463 return;
1464 }
1465
1466
1467 sub delete_type {
1468 my $type = shift;
1469
1470 App::Ack::die( qq{Internal error: Cannot delete builtin type "$type".} )
1471 unless ref $mappings{$type} eq 'ARRAY';
1472
1473 delete $mappings{$type};
1474 delete $type_wanted{$type};
1475 for my $ext ( keys %types ) {
1476 $types{$ext} = [ grep { $_ ne $type } @{$types{$ext}} ];
1477 }
1478 }
1479
1480
1481 sub ignoredir_filter {
1482 return !exists $ignore_dirs{$_};
1483 }
1484
1485
1486 sub remove_dir_sep {
1487 my $path = shift;
1488 $path =~ s/[$dir_sep_chars]$//;
1489
1490 return $path;
1491 }
1492
1493
1494 use constant TEXT => 'text';
1495
1496 sub filetypes {
1497 my $filename = shift;
1498
1499 my $basename = $filename;
1500 $basename =~ s{.*[$dir_sep_chars]}{};
1501
1502 return 'skipped' unless is_searchable( $basename );
1503
1504 my $lc_basename = lc $basename;
1505 return ('make',TEXT) if $lc_basename eq 'makefile';
1506 return ('rake','ruby',TEXT) if $lc_basename eq 'rakefile';
1507
1508 # If there's an extension, look it up
1509 if ( $filename =~ m{\.([^\.$dir_sep_chars]+)$}o ) {
1510 my $ref = $types{lc $1};
1511 return (@{$ref},TEXT) if $ref;
1512 }
1513
1514 # At this point, we can't tell from just the name. Now we have to
1515 # open it and look inside.
1516
1517 return unless -e $filename;
1518 # From Elliot Shank:
1519 # I can't see any reason that -r would fail on these-- the ACLs look
1520 # fine, and no program has any of them open, so the busted Windows
1521 # file locking model isn't getting in there. If I comment the if
1522 # statement out, everything works fine
1523 # So, for cygwin, don't bother trying to check for readability.
1524 if ( !$is_cygwin ) {
1525 if ( !-r $filename ) {
1526 App::Ack::warn( "$filename: Permission denied" );
1527 return;
1528 }
1529 }
1530
1531 return 'binary' if -B $filename;
1532
1533 # If there's no extension, or we don't recognize it, check the shebang line
1534 my $fh;
1535 if ( !open( $fh, '<', $filename ) ) {
1536 App::Ack::warn( "$filename: $!" );
1537 return;
1538 }
1539 my $header = <$fh>;
1540 close $fh;
1541
1542 if ( $header =~ /^#!/ ) {
1543 return ($1,TEXT) if $header =~ /\b(ruby|p(?:erl|hp|ython))\b/;
1544 return ('shell',TEXT) if $header =~ /\b(?:ba|t?c|k|z)?sh\b/;
1545 }
1546 else {
1547 return ('xml',TEXT) if $header =~ /\Q<?xml /i;
1548 }
1549
1550 return (TEXT);
1551 }
1552
1553
1554 sub is_searchable {
1555 my $filename = shift;
1556
1557 # If these are updated, update the --help message
1558 return if $filename =~ /[.]bak$/;
1559 return if $filename =~ /~$/;
1560 return if $filename =~ m{^#.*#$}o;
1561 return if $filename =~ m{^core\.\d+$}o;
1562 return if $filename =~ m{[._].*\.swp$}o;
1563
1564 return 1;
1565 }
1566
1567
1568 sub build_regex {
1569 my $str = shift;
1570 my $opt = shift;
1571
1572 $str = quotemeta( $str ) if $opt->{Q};
1573 if ( $opt->{w} ) {
1574 $str = "\\b$str" if $str =~ /^\w/;
1575 $str = "$str\\b" if $str =~ /\w$/;
1576 }
1577
1578 my $regex_is_lc = $str eq lc $str;
1579 if ( $opt->{i} || ($opt->{smart_case} && $regex_is_lc) ) {
1580 $str = "(?i)$str";
1581 }
1582
1583 return $str;
1584 }
1585
1586
1587 sub check_regex {
1588 my $regex = shift;
1589
1590 return unless defined $regex;
1591
1592 eval { qr/$regex/ };
1593 if ($@) {
1594 (my $error = $@) =~ s/ at \S+ line \d+.*//;
1595 chomp($error);
1596 App::Ack::die( "Invalid regex '$regex':\n $error" );
1597 }
1598
1599 return;
1600 }
1601
1602
1603
1604
1605 sub warn {
1606 return CORE::warn( _my_program(), ': ', @_, "\n" );
1607 }
1608
1609
1610 sub die {
1611 return CORE::die( _my_program(), ': ', @_, "\n" );
1612 }
1613
1614 sub _my_program {
1615 require File::Basename;
1616 return File::Basename::basename( $0 );
1617 }
1618
1619
1620
1621 sub filetypes_supported {
1622 return keys %mappings;
1623 }
1624
1625 sub _get_thpppt {
1626 my $y = q{_ /|,\\'!.x',=(www)=, U };
1627 $y =~ tr/,x!w/\nOo_/;
1628 return $y;
1629 }
1630
1631 sub _thpppt {
1632 my $y = _get_thpppt();
1633 App::Ack::print( "$y ack $_[0]!\n" );
1634 exit 0;
1635 }
1636
1637 sub _key {
1638 my $str = lc shift;
1639 $str =~ s/[^a-z]//g;
1640
1641 return $str;
1642 }
1643
1644
1645 sub show_help {
1646 my $help_arg = shift || 0;
1647
1648 return show_help_types() if $help_arg =~ /^types?/;
1649
1650 my $ignore_dirs = _listify( sort { _key($a) cmp _key($b) } keys %ignore_dirs );
1651
1652 App::Ack::print( <<"END_OF_HELP" );
1653 Usage: ack [OPTION]... PATTERN [FILE]
1654
1655 Search for PATTERN in each source file in the tree from cwd on down.
1656 If [FILES] is specified, then only those files/directories are checked.
1657 ack may also search STDIN, but only if no FILE are specified, or if
1658 one of FILES is "-".
1659
1660 Default switches may be specified in ACK_OPTIONS environment variable or
1661 an .ackrc file. If you want no dependency on the environment, turn it
1662 off with --noenv.
1663
1664 Example: ack -i select
1665
1666 Searching:
1667 -i, --ignore-case Ignore case distinctions in PATTERN
1668 --[no]smart-case Ignore case distinctions in PATTERN,
1669 only if PATTERN contains no upper case
1670 Ignored if -i is specified
1671 -v, --invert-match Invert match: select non-matching lines
1672 -w, --word-regexp Force PATTERN to match only whole words
1673 -Q, --literal Quote all metacharacters; PATTERN is literal
1674
1675 Search output:
1676 --line=NUM Only print line(s) NUM of each file
1677 -l, --files-with-matches
1678 Only print filenames containing matches
1679 -L, --files-without-matches
1680 Only print filenames with no matches
1681 -o Show only the part of a line matching PATTERN
1682 (turns off text highlighting)
1683 --passthru Print all lines, whether matching or not
1684 --output=expr Output the evaluation of expr for each line
1685 (turns off text highlighting)
1686 --match PATTERN Specify PATTERN explicitly.
1687 -m, --max-count=NUM Stop searching in each file after NUM matches
1688 -1 Stop searching after one match of any kind
1689 -H, --with-filename Print the filename for each match
1690 -h, --no-filename Suppress the prefixing filename on output
1691 -c, --count Show number of lines matching per file
1692 --column Show the column number of the first match
1693
1694 -A NUM, --after-context=NUM
1695 Print NUM lines of trailing context after matching
1696 lines.
1697 -B NUM, --before-context=NUM
1698 Print NUM lines of leading context before matching
1699 lines.
1700 -C [NUM], --context[=NUM]
1701 Print NUM lines (default 2) of output context.
1702
1703 --print0 Print null byte as separator between filenames,
1704 only works with -f, -g, -l, -L or -c.
1705
1706 File presentation:
1707 --pager=COMMAND Pipes all ack output through COMMAND. For example,
1708 --pager="less -R". Ignored if output is redirected.
1709 --nopager Do not send output through a pager. Cancels any
1710 setting in ~/.ackrc, ACK_PAGER or ACK_PAGER_COLOR.
1711 --[no]heading Print a filename heading above each file's results.
1712 (default: on when used interactively)
1713 --[no]break Print a break between results from different files.
1714 (default: on when used interactively)
1715 --group Same as --heading --break
1716 --nogroup Same as --noheading --nobreak
1717 --[no]color Highlight the matching text (default: on unless
1718 output is redirected, or on Windows)
1719 --[no]colour Same as --[no]color
1720 --color-filename=COLOR
1721 --color-match=COLOR Set the color for matches and filenames.
1722 --flush Flush output immediately, even when ack is used
1723 non-interactively (when output goes to a pipe or
1724 file).
1725
1726 File finding:
1727 -f Only print the files found, without searching.
1728 The PATTERN must not be specified.
1729 -g REGEX Same as -f, but only print files matching REGEX.
1730 --sort-files Sort the found files lexically.
1731
1732 File inclusion/exclusion:
1733 -a, --all-types All file types searched;
1734 Ignores CVS, .svn and other ignored directories
1735 -u, --unrestricted All files and directories searched
1736 --[no]ignore-dir=name Add/Remove directory from the list of ignored dirs
1737 -r, -R, --recurse Recurse into subdirectories (ack's default behavior)
1738 -n, --no-recurse No descending into subdirectories
1739 -G REGEX Only search files that match REGEX
1740
1741 --perl Include only Perl files.
1742 --type=perl Include only Perl files.
1743 --noperl Exclude Perl files.
1744 --type=noperl Exclude Perl files.
1745 See "ack --help type" for supported filetypes.
1746
1747 --type-set TYPE=.EXTENSION[,.EXT2[,...]]
1748 Files with the given EXTENSION(s) are recognized as
1749 being of type TYPE. This replaces an existing
1750 definition for type TYPE.
1751 --type-add TYPE=.EXTENSION[,.EXT2[,...]]
1752 Files with the given EXTENSION(s) are recognized as
1753 being of (the existing) type TYPE
1754
1755 --[no]follow Follow symlinks. Default is off.
1756
1757 Directories ignored by default:
1758 $ignore_dirs
1759
1760 Files not checked for type:
1761 /~\$/ - Unix backup files
1762 /#.+#\$/ - Emacs swap files
1763 /[._].*\\.swp\$/ - Vi(m) swap files
1764 /core\\.\\d+\$/ - core dumps
1765
1766 Miscellaneous:
1767 --noenv Ignore environment variables and ~/.ackrc
1768 --help This help
1769 --man Man page
1770 --version Display version & copyright
1771 --thpppt Bill the Cat
1772
1773 Exit status is 0 if match, 1 if no match.
1774
1775 This is version $VERSION of ack.
1776 END_OF_HELP
1777
1778 return;
1779 }
1780
1781
1782
1783 sub show_help_types {
1784 App::Ack::print( <<'END_OF_HELP' );
1785 Usage: ack [OPTION]... PATTERN [FILES]
1786
1787 The following is the list of filetypes supported by ack. You can
1788 specify a file type with the --type=TYPE format, or the --TYPE
1789 format. For example, both --type=perl and --perl work.
1790
1791 Note that some extensions may appear in multiple types. For example,
1792 .pod files are both Perl and Parrot.
1793
1794 END_OF_HELP
1795
1796 my @types = filetypes_supported();
1797 my $maxlen = 0;
1798 for ( @types ) {
1799 $maxlen = length if $maxlen < length;
1800 }
1801 for my $type ( sort @types ) {
1802 next if $type =~ /^-/; # Stuff to not show
1803 my $ext_list = $mappings{$type};
1804
1805 if ( ref $ext_list ) {
1806 $ext_list = join( ' ', map { ".$_" } @{$ext_list} );
1807 }
1808 App::Ack::print( sprintf( " --[no]%-*.*s %s\n", $maxlen, $maxlen, $type, $ext_list ) );
1809 }
1810
1811 return;
1812 }
1813
1814 sub _listify {
1815 my @whats = @_;
1816
1817 return '' if !@whats;
1818
1819 my $end = pop @whats;
1820 my $str = @whats ? join( ', ', @whats ) . " and $end" : $end;
1821
1822 no warnings 'once';
1823 require Text::Wrap;
1824 $Text::Wrap::columns = 75;
1825 return Text::Wrap::wrap( '', ' ', $str );
1826 }
1827
1828
1829 sub get_version_statement {
1830 require Config;
1831
1832 my $copyright = get_copyright();
1833 my $this_perl = $Config::Config{perlpath};
1834 if ($^O ne 'VMS') {
1835 my $ext = $Config::Config{_exe};
1836 $this_perl .= $ext unless $this_perl =~ m/$ext$/i;
1837 }
1838 my $ver = sprintf( '%vd', $^V );
1839
1840 return <<"END_OF_VERSION";
1841 ack $VERSION
1842 Running under Perl $ver at $this_perl
1843
1844 $copyright
1845
1846 This program is free software; you can redistribute it and/or modify
1847 it under the terms of either: the GNU General Public License as
1848 published by the Free Software Foundation; or the Artistic License.
1849 END_OF_VERSION
1850 }
1851
1852
1853 sub print_version_statement {
1854 App::Ack::print( get_version_statement() );
1855
1856 return;
1857 }
1858
1859
1860 sub get_copyright {
1861 return $COPYRIGHT;
1862 }
1863
1864
1865 sub load_colors {
1866 eval 'use Term::ANSIColor ()';
1867
1868 $ENV{ACK_COLOR_MATCH} ||= 'black on_yellow';
1869 $ENV{ACK_COLOR_FILENAME} ||= 'bold green';
1870
1871 return;
1872 }
1873
1874
1875 sub is_interesting {
1876 return if /^\./;
1877
1878 my $include;
1879
1880 for my $type ( filetypes( $File::Next::name ) ) {
1881 if ( defined $type_wanted{$type} ) {
1882 if ( $type_wanted{$type} ) {
1883 $include = 1;
1884 }
1885 else {
1886 return;
1887 }
1888 }
1889 }
1890
1891 return $include;
1892 }
1893
1894
1895
1896 # print subs added in order to make it easy for a third party
1897 # module (such as App::Wack) to redefine the display methods
1898 # and show the results in a different way.
1899 sub print { print {$fh} @_ }
1900 sub print_first_filename { App::Ack::print( $_[0], "\n" ) }
1901 sub print_blank_line { App::Ack::print( "\n" ) }
1902 sub print_separator { App::Ack::print( "--\n" ) }
1903 sub print_filename { App::Ack::print( $_[0], $_[1] ) }
1904 sub print_line_no { App::Ack::print( $_[0], $_[1] ) }
1905 sub print_column_no { App::Ack::print( $_[0], $_[1] ) }
1906 sub print_count {
1907 my $filename = shift;
1908 my $nmatches = shift;
1909 my $ors = shift;
1910 my $count = shift;
1911
1912 App::Ack::print( $filename );
1913 App::Ack::print( ':', $nmatches ) if $count;
1914 App::Ack::print( $ors );
1915 }
1916
1917 sub print_count0 {
1918 my $filename = shift;
1919 my $ors = shift;
1920
1921 App::Ack::print( $filename, ':0', $ors );
1922 }
1923
1924
1925
1926 {
1927 my $filename;
1928 my $regex;
1929 my $display_filename;
1930
1931 my $keep_context;
1932
1933 my $last_output_line; # number of the last line that has been output
1934 my $any_output; # has there been any output for the current file yet
1935 my $context_overall_output_count; # has there been any output at all
1936
1937 sub search_resource {
1938 my $res = shift;
1939 my $opt = shift;
1940
1941 $filename = $res->name();
1942
1943 my $v = $opt->{v};
1944 my $passthru = $opt->{passthru};
1945 my $max = $opt->{m};
1946 my $nmatches = 0;
1947
1948 $display_filename = undef;
1949
1950 # for --line processing
1951 my $has_lines = 0;
1952 my @lines;
1953 if ( defined $opt->{lines} ) {
1954 $has_lines = 1;
1955 @lines = ( @{$opt->{lines}}, -1 );
1956 undef $regex; # Don't match when printing matching line
1957 }
1958 else {
1959 $regex = qr/$opt->{regex}/;
1960 }
1961
1962 # for context processing
1963 $last_output_line = -1;
1964 $any_output = 0;
1965 my $before_context = $opt->{before_context};
1966 my $after_context = $opt->{after_context};
1967
1968 $keep_context = ($before_context || $after_context) && !$passthru;
1969
1970 my @before;
1971 my $before_starts_at_line;
1972 my $after = 0; # number of lines still to print after a match
1973
1974 while ( $res->next_text ) {
1975 # XXX Optimize away the case when there are no more @lines to find.
1976 # XXX $has_lines, $passthru and $v never change. Optimize.
1977 if ( $has_lines
1978 ? $. != $lines[0] # $lines[0] should be a scalar
1979 : $v ? m/$regex/ : !m/$regex/ ) {
1980 if ( $passthru ) {
1981 App::Ack::print( $_ );
1982 next;
1983 }
1984
1985 if ( $keep_context ) {
1986 if ( $after ) {
1987 print_match_or_context( $opt, 0, $., $-[0], $+[0], $_ );
1988 $after--;
1989 }
1990 elsif ( $before_context ) {
1991 if ( @before ) {
1992 if ( @before >= $before_context ) {
1993 shift @before;
1994 ++$before_starts_at_line;
1995 }
1996 }
1997 else {
1998 $before_starts_at_line = $.;
1999 }
2000 push @before, $_;
2001 }
2002 last if $max && ( $nmatches >= $max ) && !$after;
2003 }
2004 next;
2005 } # not a match
2006
2007 ++$nmatches;
2008
2009 # print an empty line as a divider before first line in each file (not before the first file)
2010 if ( !$any_output && $opt->{show_filename} && $opt->{break} && defined( $context_overall_output_count ) ) {
2011 App::Ack::print_blank_line();
2012 }
2013
2014 shift @lines if $has_lines;
2015
2016 if ( $res->is_binary ) {
2017 App::Ack::print( "Binary file $filename matches\n" );
2018 last;
2019 }
2020 if ( $keep_context ) {
2021 if ( @before ) {
2022 print_match_or_context( $opt, 0, $before_starts_at_line, $-[0], $+[0], @before );
2023 @before = ();
2024 $before_starts_at_line = 0;
2025 }
2026 if ( $max && $nmatches > $max ) {
2027 --$after;
2028 }
2029 else {
2030 $after = $after_context;
2031 }
2032 }
2033 print_match_or_context( $opt, 1, $., $-[0], $+[0], $_ );
2034
2035 last if $max && ( $nmatches >= $max ) && !$after;
2036 } # while
2037
2038 return $nmatches;
2039 } # search_resource()
2040
2041
2042
2043 sub print_match_or_context {
2044 my $opt = shift; # opts array
2045 my $is_match = shift; # is there a match on the line?
2046 my $line_no = shift;
2047 my $match_start = shift;
2048 my $match_end = shift;
2049
2050 my $color = $opt->{color};
2051 my $heading = $opt->{heading};
2052 my $show_filename = $opt->{show_filename};
2053 my $show_column = $opt->{column};
2054
2055 if ( $show_filename ) {
2056 if ( not defined $display_filename ) {
2057 $display_filename =
2058 $color
2059 ? Term::ANSIColor::colored( $filename, $ENV{ACK_COLOR_FILENAME} )
2060 : $filename;
2061 if ( $heading && !$any_output ) {
2062 App::Ack::print_first_filename($display_filename);
2063 }
2064 }
2065 }
2066
2067 my $sep = $is_match ? ':' : '-';
2068 my $output_func = $opt->{output};
2069 for ( @_ ) {
2070 if ( $keep_context && !$output_func ) {
2071 if ( ( $last_output_line != $line_no - 1 ) &&
2072 ( $any_output || ( !$heading && defined( $context_overall_output_count ) ) ) ) {
2073 App::Ack::print_separator();
2074 }
2075 # to ensure separators between different files when --noheading
2076
2077 $last_output_line = $line_no;
2078 }
2079
2080 if ( $show_filename ) {
2081 App::Ack::print_filename($display_filename, $sep) if not $heading;
2082 App::Ack::print_line_no($line_no, $sep);
2083 }
2084
2085 if ( $output_func ) {
2086 while ( /$regex/go ) {
2087 App::Ack::print( $output_func->() . "\n" );
2088 }
2089 }
2090 else {
2091 if ( $color && $is_match && $regex &&
2092 s/$regex/Term::ANSIColor::colored( substr($_, $-[0], $+[0] - $-[0]), $ENV{ACK_COLOR_MATCH} )/eg ) {
2093 # At the end of the line reset the color and remove newline
2094 s/[\r\n]*\z/\e[0m\e[K/;
2095 }
2096 else {
2097 # remove any kind of newline at the end of the line
2098 s/[\r\n]*\z//;
2099 }
2100 if ( $show_column ) {
2101 App::Ack::print_column_no( $match_start+1, $sep );
2102 }
2103 App::Ack::print($_ . "\n");
2104 }
2105 $any_output = 1;
2106 ++$context_overall_output_count;
2107 ++$line_no;
2108 }
2109
2110 return;
2111 } # print_match_or_context()
2112
2113 } # scope around search_resource() and print_match_or_context()
2114
2115
2116
2117 sub search_and_list {
2118 my $res = shift;
2119 my $opt = shift;
2120
2121 my $nmatches = 0;
2122 my $count = $opt->{count};
2123 my $ors = $opt->{print0} ? "\0" : "\n"; # output record separator
2124
2125 my $regex = qr/$opt->{regex}/;
2126
2127 if ( $opt->{v} ) {
2128 while ( $res->next_text ) {
2129 if ( /$regex/ ) {
2130 return 0 unless $count;
2131 }
2132 else {
2133 ++$nmatches;
2134 }
2135 }
2136 }
2137 else {
2138 while ( $res->next_text ) {
2139 if ( /$regex/ ) {
2140 ++$nmatches;
2141 last unless $count;
2142 }
2143 }
2144 }
2145
2146 if ( $nmatches ) {
2147 App::Ack::print_count( $res->name, $nmatches, $ors, $count );
2148 }
2149 elsif ( $count && !$opt->{l} ) {
2150 App::Ack::print_count0( $res->name, $ors );
2151 }
2152
2153 return $nmatches ? 1 : 0;
2154 } # search_and_list()
2155
2156
2157
2158 sub filetypes_supported_set {
2159 return grep { defined $type_wanted{$_} && ($type_wanted{$_} == 1) } filetypes_supported();
2160 }
2161
2162
2163
2164 sub print_files {
2165 my $iter = shift;
2166 my $opt = shift;
2167
2168 my $ors = $opt->{print0} ? "\0" : "\n";
2169
2170 my $nmatches = 0;
2171 while ( defined ( my $file = $iter->() ) ) {
2172 App::Ack::print $file, $ors;
2173 $nmatches++;
2174 last if $opt->{1};
2175 }
2176
2177 return $nmatches;
2178 }
2179
2180
2181 sub print_files_with_matches {
2182 my $iter = shift;
2183 my $opt = shift;
2184
2185 my $nmatches = 0;
2186 while ( defined ( my $filename = $iter->() ) ) {
2187 my $repo = App::Ack::Repository::Basic->new( $filename );
2188 my $res;
2189 while ( $res = $repo->next_resource() ) {
2190 $nmatches += search_and_list( $res, $opt );
2191 $res->close();
2192 last if $nmatches && $opt->{1};
2193 }
2194 $repo->close();
2195 }
2196
2197 return $nmatches;
2198 }
2199
2200
2201 sub print_matches {
2202 my $iter = shift;
2203 my $opt = shift;
2204
2205 $opt->{show_filename} = 0 if $opt->{h};
2206 $opt->{show_filename} = 1 if $opt->{H};
2207
2208 my $nmatches = 0;
2209 while ( defined ( my $filename = $iter->() ) ) {
2210 my $repo;
2211 my $tarballs_work = 0;
2212 if ( $tarballs_work && $filename =~ /\.tar\.gz$/ ) {
2213 App::Ack::die( 'Not working here yet' );
2214 require App::Ack::Repository::Tar; # XXX Error checking
2215 $repo = App::Ack::Repository::Tar->new( $filename );
2216 }
2217 else {
2218 $repo = App::Ack::Repository::Basic->new( $filename );
2219 }
2220 $repo or next;
2221
2222 while ( my $res = $repo->next_resource() ) {
2223 my $needs_line_scan;
2224 if ( $opt->{regex} && !$opt->{passthru} ) {
2225 $needs_line_scan = $res->needs_line_scan( $opt );
2226 if ( $needs_line_scan ) {
2227 $res->reset();
2228 }
2229 }
2230 else {
2231 $needs_line_scan = 1;
2232 }
2233 if ( $needs_line_scan ) {
2234 $nmatches += search_resource( $res, $opt );
2235 }
2236 $res->close();
2237 }
2238 last if $nmatches && $opt->{1};
2239 $repo->close();
2240 }
2241 return $nmatches;
2242 }
2243
2244
2245 sub filetype_setup {
2246 my $filetypes_supported_set = filetypes_supported_set();
2247 # If anyone says --no-whatever, we assume all other types must be on.
2248 if ( !$filetypes_supported_set ) {
2249 for my $i ( keys %type_wanted ) {
2250 $type_wanted{$i} = 1 unless ( defined( $type_wanted{$i} ) || $i eq 'binary' || $i eq 'text' || $i eq 'skipped' );
2251 }
2252 }
2253 return;
2254 }
2255
2256
2257 EXPAND_FILENAMES_SCOPE: {
2258 my $filter;
2259
2260 sub expand_filenames {
2261 my $argv = shift;
2262
2263 my $attr;
2264 my @files;
2265
2266 foreach my $pattern ( @{$argv} ) {
2267 my @results = bsd_glob( $pattern );
2268
2269 if (@results == 0) {
2270 @results = $pattern; # Glob didn't match, pass it thru unchanged
2271 }
2272 elsif ( (@results > 1) or ($results[0] ne $pattern) ) {
2273 if (not defined $filter) {
2274 eval 'require Win32::File;';
2275 if ($@) {
2276 $filter = 0;
2277 }
2278 else {
2279 $filter = Win32::File::HIDDEN()|Win32::File::SYSTEM();
2280 }
2281 } # end unless we've tried to load Win32::File
2282 if ( $filter ) {
2283 # Filter out hidden and system files:
2284 @results = grep { not(Win32::File::GetAttributes($_, $attr) and $attr & $filter) } @results;
2285 App::Ack::warn( "$pattern: Matched only hidden files" ) unless @results;
2286 } # end if we can filter by file attributes
2287 } # end elsif this pattern got expanded
2288
2289 push @files, @results;
2290 } # end foreach pattern
2291
2292 return \@files;
2293 } # end expand_filenames
2294 } # EXPAND_FILENAMES_SCOPE
2295
2296
2297
2298 sub get_starting_points {
2299 my $argv = shift;
2300 my $opt = shift;
2301
2302 my @what;
2303
2304 if ( @{$argv} ) {
2305 @what = @{ $is_windows ? expand_filenames($argv) : $argv };
2306 $_ = File::Next::reslash( $_ ) for @what;
2307
2308 # Show filenames unless we've specified one single file
2309 $opt->{show_filename} = (@what > 1) || (!-f $what[0]);
2310 }
2311 else {
2312 @what = '.'; # Assume current directory
2313 $opt->{show_filename} = 1;
2314 }
2315
2316 for my $start_point (@what) {
2317 App::Ack::warn( "$start_point: No such file or directory" ) unless -e $start_point;
2318 }
2319 return \@what;
2320 }
2321
2322
2323
2324 sub get_iterator {
2325 my $what = shift;
2326 my $opt = shift;
2327
2328 # Starting points are always searched, no matter what
2329 my %starting_point = map { ($_ => 1) } @{$what};
2330
2331 my $g_regex = defined $opt->{G} ? qr/$opt->{G}/ : undef;
2332 my $file_filter;
2333
2334 if ( $g_regex ) {
2335 $file_filter
2336 = $opt->{u} ? sub { $File::Next::name =~ /$g_regex/ } # XXX Maybe this should be a 1, no?
2337 : $opt->{all} ? sub { $starting_point{ $File::Next::name } || ( $File::Next::name =~ /$g_regex/ && is_searchable( $_ ) ) }
2338 : sub { $starting_point{ $File::Next::name } || ( $File::Next::name =~ /$g_regex/ && is_interesting( @_ ) ) }
2339 ;
2340 }
2341 else {
2342 $file_filter
2343 = $opt->{u} ? sub {1}
2344 : $opt->{all} ? sub { $starting_point{ $File::Next::name } || is_searchable( $_ ) }
2345 : sub { $starting_point{ $File::Next::name } || is_interesting( @_ ) }
2346 ;
2347 }
2348
2349 my $descend_filter
2350 = $opt->{n} ? sub {0}
2351 : $opt->{u} ? sub {1}
2352 : \&ignoredir_filter;
2353
2354 my $iter =
2355 File::Next::files( {
2356 file_filter => $file_filter,
2357 descend_filter => $descend_filter,
2358 error_handler => sub { my $msg = shift; App::Ack::warn( $msg ) },
2359 sort_files => $opt->{sort_files},
2360 follow_symlinks => $opt->{follow},
2361 }, @{$what} );
2362 return $iter;
2363 }
2364
2365
2366 sub set_up_pager {
2367 my $command = shift;
2368
2369 return if App::Ack::output_to_pipe();
2370
2371 my $pager;
2372 if ( not open( $pager, '|-', $command ) ) {
2373 App::Ack::die( qq{Unable to pipe to pager "$command": $!} );
2374 }
2375 $fh = $pager;
2376
2377 return;
2378 }
2379
2380
2381 sub input_from_pipe {
2382 return $input_from_pipe;
2383 }
2384
2385
2386
2387 sub output_to_pipe {
2388 return $output_to_pipe;
2389 }
2390
2391
2392
2393 1; # End of App::Ack
2394 package App::Ack::Repository;
2395
2396
2397 use warnings;
2398 use strict;
2399
2400 sub FAIL {
2401 require Carp;
2402 Carp::confess( 'Must be overloaded' );
2403 }
2404
2405
2406 sub new {
2407 FAIL();
2408 }
2409
2410
2411 sub next_resource {
2412 FAIL();
2413 }
2414
2415
2416 sub close {
2417 FAIL();
2418 }
2419
2420 1;
2421 package App::Ack::Resource;
2422
2423
2424 use warnings;
2425 use strict;
2426
2427 sub FAIL {
2428 require Carp;
2429 Carp::confess( 'Must be overloaded' );
2430 }
2431
2432
2433 sub new {
2434 FAIL();
2435 }
2436
2437
2438 sub name {
2439 FAIL();
2440 }
2441
2442
2443 sub is_binary {
2444 FAIL();
2445 }
2446
2447
2448
2449 sub needs_line_scan {
2450 FAIL();
2451 }
2452
2453
2454 sub reset {
2455 FAIL();
2456 }
2457
2458
2459 sub next_text {
2460 FAIL();
2461 }
2462
2463
2464 sub close {
2465 FAIL();
2466 }
2467
2468 1;
2469 package App::Ack::Plugin::Basic;
2470
2471
2472
2473 package App::Ack::Resource::Basic;
2474
2475
2476 use warnings;
2477 use strict;
2478
2479
2480 our @ISA = qw( App::Ack::Resource );
2481
2482
2483 sub new {
2484 my $class = shift;
2485 my $filename = shift;
2486
2487 my $self = bless {
2488 filename => $filename,
2489 fh => undef,
2490 could_be_binary => undef,
2491 opened => undef,
2492 id => undef,
2493 }, $class;
2494
2495 if ( $self->{filename} eq '-' ) {
2496 $self->{fh} = *STDIN;
2497 $self->{could_be_binary} = 0;
2498 }
2499 else {
2500 if ( !open( $self->{fh}, '<', $self->{filename} ) ) {
2501 App::Ack::warn( "$self->{filename}: $!" );
2502 return;
2503 }
2504 $self->{could_be_binary} = 1;
2505 }
2506
2507 return $self;
2508 }
2509
2510
2511 sub name {
2512 my $self = shift;
2513
2514 return $self->{filename};
2515 }
2516
2517
2518 sub is_binary {
2519 my $self = shift;
2520
2521 if ( $self->{could_be_binary} ) {
2522 return -B $self->{filename};
2523 }
2524
2525 return 0;
2526 }
2527
2528
2529
2530 sub needs_line_scan {
2531 my $self = shift;
2532 my $opt = shift;
2533
2534 return 1 if $opt->{v};
2535
2536 my $size = -s $self->{fh};
2537 if ( $size == 0 ) {
2538 return 0;
2539 }
2540 elsif ( $size > 100_000 ) {
2541 return 1;
2542 }
2543
2544 my $buffer;
2545 my $rc = sysread( $self->{fh}, $buffer, $size );
2546 if ( not defined $rc ) {
2547 App::Ack::warn( "$self->{filename}: $!" );
2548 return 1;
2549 }
2550 return 0 unless $rc && ( $rc == $size );
2551
2552 my $regex = $opt->{regex};
2553 return $buffer =~ /$regex/m;
2554 }
2555
2556
2557 sub reset {
2558 my $self = shift;
2559
2560 seek( $self->{fh}, 0, 0 )
2561 or App::Ack::warn( "$self->{filename}: $!" );
2562
2563 return;
2564 }
2565
2566
2567 sub next_text {
2568 if ( defined ($_ = readline $_[0]->{fh}) ) {
2569 $. = ++$_[0]->{line};
2570 return 1;
2571 }
2572
2573 return;
2574 }
2575
2576
2577 sub close {
2578 my $self = shift;
2579
2580 if ( not close $self->{fh} ) {
2581 App::Ack::warn( $self->name() . ": $!" );
2582 }
2583
2584 return;
2585 }
2586
2587 package App::Ack::Repository::Basic;
2588
2589
2590 our @ISA = qw( App::Ack::Repository );
2591
2592
2593 use warnings;
2594 use strict;
2595
2596 sub new {
2597 my $class = shift;
2598 my $filename = shift;
2599
2600 my $self = bless {
2601 filename => $filename,
2602 nexted => 0,
2603 }, $class;
2604
2605 return $self;
2606 }
2607
2608
2609 sub next_resource {
2610 my $self = shift;
2611
2612 return if $self->{nexted};
2613 $self->{nexted} = 1;
2614
2615 return App::Ack::Resource::Basic->new( $self->{filename} );
2616 }
2617
2618
2619 sub close {
2620 }
2621
2622
2623
2624 1;