]> Tony Duckles's Git Repositories (git.nynim.org) - dotfiles.git/blob - bin/ack
bin/ack: ack 2.02
[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/ack2
8 # and submit patches against the individual files
9 # that build ack.
10 #
11
12 use strict;
13 use warnings;
14
15 use 5.008;
16
17
18 # XXX Don't make this so brute force
19 # See also: https://github.com/petdance/ack2/issues/89
20
21 use Getopt::Long 2.36 ();
22
23 use Carp 1.04 ();
24
25 our $VERSION = '2.02';
26 # Check http://beyondgrep.com/ for updates
27
28 # These are all our globals.
29
30 MAIN: {
31 $App::Ack::orig_program_name = $0;
32 $0 = join(' ', 'ack', $0);
33 if ( $App::Ack::VERSION ne $main::VERSION ) {
34 App::Ack::die( "Program/library version mismatch\n\t$0 is $main::VERSION\n\t$INC{'App/Ack.pm'} is $App::Ack::VERSION" );
35 }
36
37 # Do preliminary arg checking;
38 my $env_is_usable = 1;
39 for ( @ARGV ) {
40 last if ( $_ eq '--' );
41
42 # Get the --thpppt and --bar checking out of the way.
43 /^--th[pt]+t+$/ && App::Ack::_thpppt($_);
44 /^--bar$/ && App::Ack::_bar();
45
46 # See if we want to ignore the environment. (Don't tell Al Gore.)
47 if ( /^--(no)?env$/ ) {
48 $env_is_usable = defined $1 ? 0 : 1;
49 }
50 }
51 if ( !$env_is_usable ) {
52 my @keys = ( 'ACKRC', grep { /^ACK_/ } keys %ENV );
53 delete @ENV{@keys};
54 }
55 App::Ack::load_colors();
56
57 Getopt::Long::Configure('default', 'no_auto_help', 'no_auto_version');
58 Getopt::Long::Configure('pass_through', 'no_auto_abbrev');
59 Getopt::Long::GetOptions(
60 'help' => sub { App::Ack::show_help(); exit; },
61 'version' => sub { App::Ack::print_version_statement(); exit; },
62 'man' => sub { App::Ack::show_man(); exit; },
63 );
64 Getopt::Long::Configure('default', 'no_auto_help', 'no_auto_version');
65
66 if ( !@ARGV ) {
67 App::Ack::show_help();
68 exit 1;
69 }
70
71 main();
72 }
73
74 sub _compile_descend_filter {
75 my ( $opt ) = @_;
76
77 my $idirs = $opt->{idirs};
78 my $dont_ignore_dirs = $opt->{no_ignore_dirs};
79
80 # if we have one or more --noignore-dir directives, we can't ignore
81 # entire subdirectory hierarchies, so we return an "accept all"
82 # filter and scrutinize the files more in _compile_file_filter
83 return if $dont_ignore_dirs;
84 return unless $idirs && @{$idirs};
85
86 my %ignore_dirs;
87
88 foreach my $idir (@{$idirs}) {
89 if ( $idir =~ /^(\w+):(.*)/ ) {
90 if ( $1 eq 'is') {
91 $ignore_dirs{$2} = 1;
92 }
93 else {
94 Carp::croak( 'Non-is filters are not yet supported for --ignore-dir' );
95 }
96 }
97 else {
98 Carp::croak( qq{Invalid filter specification "$idir"} );
99 }
100 }
101
102 return sub {
103 return !exists $ignore_dirs{$_} && !exists $ignore_dirs{$File::Next::dir};
104 };
105 }
106
107 sub _compile_file_filter {
108 my ( $opt, $start ) = @_;
109
110 my $ifiles = $opt->{ifiles};
111 $ifiles ||= [];
112
113 my @ifiles_filters = map {
114 my $filter;
115
116 if ( /^(\w+):(.+)/ ) {
117 my ($how,$what) = ($1,$2);
118 $filter = App::Ack::Filter->create_filter($how, split(/,/, $what));
119 }
120 else {
121 Carp::croak( qq{Invalid filter specification "$_"} );
122 }
123 $filter
124 } @{$ifiles};
125
126 my $filters = $opt->{'filters'} || [];
127 my $inverse_filters = [ grep { $_->is_inverted() } @{$filters} ];
128 @{$filters} = grep { !$_->is_inverted() } @{$filters};
129
130 my %is_member_of_starting_set = map { (App::Ack::get_file_id($_) => 1) } @{$start};
131
132 my $ignore_dir_list = $opt->{idirs};
133 my $dont_ignore_dir_list = $opt->{no_ignore_dirs};
134
135 my %ignore_dir_set;
136 my %dont_ignore_dir_set;
137
138 foreach my $filter (@{ $ignore_dir_list }) {
139 if ( $filter =~ /^(\w+):(.*)/ ) {
140 if ( $1 eq 'is' ) {
141 $ignore_dir_set{ $2 } = 1;
142 } else {
143 Carp::croak( 'Non-is filters are not yet supported for --ignore-dir' );
144 }
145 } else {
146 Carp::croak( qq{Invalid filter specification "$filter"} );
147 }
148 }
149 foreach my $filter (@{ $dont_ignore_dir_list }) {
150 if ( $filter =~ /^(\w+):(.*)/ ) {
151 if ( $1 eq 'is' ) {
152 $dont_ignore_dir_set{ $2 } = 1;
153 } else {
154 Carp::croak( 'Non-is filters are not yet supported for --ignore-dir' );
155 }
156 } else {
157 Carp::croak( qq{Invalid filter specification "$filter"} );
158 }
159 }
160
161 return sub {
162 # ack always selects files that are specified on the command
163 # line, regardless of filetype. If you want to ack a JPEG,
164 # and say "ack foo whatever.jpg" it will do it for you.
165 return 1 if $is_member_of_starting_set{ App::Ack::get_file_id($File::Next::name) };
166
167 if ( $dont_ignore_dir_list ) {
168 my ( undef, $dirname ) = File::Spec->splitpath($File::Next::name);
169 my @dirs = File::Spec->splitdir($dirname);
170
171 my $is_ignoring = 0;
172
173 foreach my $dir ( @dirs ) {
174 if ( $ignore_dir_set{ $dir } ) {
175 $is_ignoring = 1;
176 }
177 elsif ( $dont_ignore_dir_set{ $dir } ) {
178 $is_ignoring = 0;
179 }
180 }
181 if ( $is_ignoring ) {
182 return 0;
183 }
184 }
185
186 # Ignore named pipes found in directory searching. Named
187 # pipes created by subprocesses get specified on the command
188 # line, so the rule of "always select whatever is on the
189 # command line" wins.
190 return 0 if -p $File::Next::name;
191
192 foreach my $filter (@ifiles_filters) {
193 my $resource = App::Ack::Resource::Basic->new($File::Next::name);
194 return 0 if ! $resource || $filter->filter($resource);
195 }
196 my $match_found = 1;
197 if ( @{$filters} ) {
198 $match_found = 0;
199
200 foreach my $filter (@{$filters}) {
201 my $resource = App::Ack::Resource::Basic->new($File::Next::name);
202 return 0 if ! $resource;
203 if ($filter->filter($resource)) {
204 $match_found = 1;
205 last;
206 }
207 }
208 }
209 # Don't bother invoking inverse filters unless we consider the current resource a match
210 if ( $match_found && @{$inverse_filters} ) {
211 foreach my $filter ( @{$inverse_filters} ) {
212 my $resource = App::Ack::Resource::Basic->new($File::Next::name);
213 return 0 if ! $resource;
214 if ( not $filter->filter( $resource ) ) {
215 $match_found = 0;
216 last;
217 }
218 }
219 }
220 return $match_found;
221 };
222 }
223
224 sub show_types {
225 my $resource = shift;
226 my $ors = shift;
227
228 my @types = App::Ack::filetypes( $resource );
229 my $types = join( ',', @types );
230 my $arrow = @types ? ' => ' : ' =>';
231 App::Ack::print( $resource->name, $arrow, join( ',', @types ), $ors );
232
233 return;
234 }
235
236 sub main {
237 my @arg_sources = App::Ack::retrieve_arg_sources();
238
239 my $opt = App::Ack::ConfigLoader::process_args( @arg_sources );
240
241 $App::Ack::report_bad_filenames = !$opt->{dont_report_bad_filenames};
242
243 if ( $opt->{flush} ) {
244 $| = 1;
245 }
246
247 if ( not defined $opt->{color} ) {
248 $opt->{color} = !App::Ack::output_to_pipe() && !$App::Ack::is_windows;
249 }
250 if ( not defined $opt->{heading} and not defined $opt->{break} ) {
251 $opt->{heading} = $opt->{break} = !App::Ack::output_to_pipe();
252 }
253
254 if ( defined($opt->{H}) || defined($opt->{h}) ) {
255 $opt->{show_filename}= $opt->{H} && !$opt->{h};
256 }
257
258 if ( my $output = $opt->{output} ) {
259 $output =~ s{\\}{\\\\}g;
260 $output =~ s{"}{\\"}g;
261 $opt->{output} = qq{"$output"};
262 }
263
264 my $resources;
265 if ( $App::Ack::is_filter_mode && !$opt->{files_from} ) { # probably -x
266 $resources = App::Ack::Resources->from_stdin( $opt );
267 my $regex = $opt->{regex};
268 $regex = shift @ARGV if not defined $regex;
269 $opt->{regex} = App::Ack::build_regex( $regex, $opt );
270 }
271 else {
272 if ( $opt->{f} || $opt->{lines} ) {
273 if ( $opt->{regex} ) {
274 App::Ack::warn( "regex ($opt->{regex}) specified with -f or --lines" );
275 App::Ack::exit_from_ack( 0 ); # XXX the 0 is misleading
276 }
277 }
278 else {
279 my $regex = $opt->{regex};
280 $regex = shift @ARGV if not defined $regex;
281 $opt->{regex} = App::Ack::build_regex( $regex, $opt );
282 }
283 my @start;
284 if ( not defined $opt->{files_from} ) {
285 @start = @ARGV;
286 }
287 if ( !exists($opt->{show_filename}) ) {
288 unless(@start == 1 && !(-d $start[0])) {
289 $opt->{show_filename} = 1;
290 }
291 }
292
293 if ( defined $opt->{files_from} ) {
294 $resources = App::Ack::Resources->from_file( $opt, $opt->{files_from} );
295 exit 1 unless $resources;
296 }
297 else {
298 @start = ('.') unless @start;
299 foreach my $target (@start) {
300 if ( !-e $target && $App::Ack::report_bad_filenames) {
301 App::Ack::warn( "$target: No such file or directory" );
302 }
303 }
304
305 $opt->{file_filter} = _compile_file_filter($opt, \@start);
306 $opt->{descend_filter} = _compile_descend_filter($opt);
307
308 $resources = App::Ack::Resources->from_argv( $opt, \@start );
309 }
310 }
311 App::Ack::set_up_pager( $opt->{pager} ) if defined $opt->{pager};
312
313 my $print_filenames = $opt->{show_filename};
314 my $max_count = $opt->{m};
315 my $ors = $opt->{print0} ? "\0" : "\n";
316 my $only_first = $opt->{1};
317
318 my $nmatches = 0;
319 my $total_count = 0;
320 RESOURCES:
321 while ( my $resource = $resources->next ) {
322 # XXX this variable name combined with what we're trying
323 # to do makes no sense.
324
325 # XXX Combine the -f and -g functions
326 if ( $opt->{f} ) {
327 # XXX printing should probably happen inside of App::Ack
328 if ( $opt->{show_types} ) {
329 show_types( $resource, $ors );
330 }
331 else {
332 App::Ack::print( $resource->name, $ors );
333 }
334 ++$nmatches;
335 last RESOURCES if defined($max_count) && $nmatches >= $max_count;
336 }
337 elsif ( $opt->{g} ) {
338 my $is_match = ( $resource->name =~ /$opt->{regex}/o );
339 if ( $opt->{v} ? !$is_match : $is_match ) {
340 if ( $opt->{show_types} ) {
341 show_types( $resource, $ors );
342 }
343 else {
344 App::Ack::print( $resource->name, $ors );
345 }
346 ++$nmatches;
347 last RESOURCES if defined($max_count) && $nmatches >= $max_count;
348 }
349 }
350 elsif ( $opt->{lines} ) {
351 my $print_filename = $opt->{show_filename};
352 my $passthru = $opt->{passthru};
353
354 my %line_numbers;
355 foreach my $line ( @{ $opt->{lines} } ) {
356 my @lines = split /,/, $line;
357 @lines = map {
358 /^(\d+)-(\d+)$/
359 ? ( $1 .. $2 )
360 : $_
361 } @lines;
362 @line_numbers{@lines} = (1) x @lines;
363 }
364
365 my $filename = $resource->name;
366
367 local $opt->{color} = 0;
368
369 App::Ack::iterate($resource, $opt, sub {
370 chomp;
371
372 if ( $line_numbers{$.} ) {
373 App::Ack::print_line_with_context($opt, $filename, $_, $.);
374 }
375 elsif ( $passthru ) {
376 App::Ack::print_line_with_options($opt, $filename, $_, $., ':');
377 }
378 return 1;
379 });
380 }
381 elsif ( $opt->{count} ) {
382 my $matches_for_this_file = App::Ack::count_matches_in_resource( $resource, $opt );
383
384 unless ( $opt->{show_filename} ) {
385 $total_count += $matches_for_this_file;
386 next RESOURCES;
387 }
388
389 if ( !$opt->{l} || $matches_for_this_file > 0) {
390 if ( $print_filenames ) {
391 App::Ack::print( $resource->name, ':', $matches_for_this_file, $ors );
392 }
393 else {
394 App::Ack::print( $matches_for_this_file, $ors );
395 }
396 }
397 }
398 elsif ( $opt->{l} || $opt->{L} ) {
399 my $is_match = App::Ack::resource_has_match( $resource, $opt );
400
401 if ( $opt->{L} ? !$is_match : $is_match ) {
402 App::Ack::print( $resource->name, $ors );
403 ++$nmatches;
404
405 last RESOURCES if $only_first;
406 last RESOURCES if defined($max_count) && $nmatches >= $max_count;
407 }
408 }
409 else {
410 $nmatches += App::Ack::print_matches_in_resource( $resource, $opt );
411 if ( $nmatches && $only_first ) {
412 last RESOURCES;
413 }
414 }
415 }
416
417 if ( $opt->{count} && !$opt->{show_filename} ) {
418 App::Ack::print( $total_count, "\n" );
419 }
420
421 close $App::Ack::fh;
422 App::Ack::exit_from_ack( $nmatches );
423 }
424
425
426 =head1 NAME
427
428 ack - grep-like text finder
429
430 =head1 SYNOPSIS
431
432 ack [options] PATTERN [FILE...]
433 ack -f [options] [DIRECTORY...]
434
435 =head1 DESCRIPTION
436
437 Ack is designed as a replacement for 99% of the uses of F<grep>.
438
439 Ack searches the named input FILEs (or standard input if no files
440 are named, or the file name - is given) for lines containing a match
441 to the given PATTERN. By default, ack prints the matching lines.
442
443 PATTERN is a Perl regular expression. Perl regular expressions
444 are commonly found in other programming languages, but for the particulars
445 of their behavior, please consult
446 L<http://perldoc.perl.org/perlreref.html|perlreref>. If you don't know
447 how to use regular expression but are interested in learning, you may
448 consult L<http://perldoc.perl.org/perlretut.html|perlretut>. If you do not
449 need or want ack to use regular expressions, please see the
450 C<-Q>/C<--literal> option.
451
452 Ack can also list files that would be searched, without actually
453 searching them, to let you take advantage of ack's file-type filtering
454 capabilities.
455
456 =head1 FILE SELECTION
457
458 If files are not specified for searching, either on the command
459 line or piped in with the C<-x> option, I<ack> delves into
460 subdirectories selecting files for searching.
461
462 I<ack> is intelligent about the files it searches. It knows about
463 certain file types, based on both the extension on the file and,
464 in some cases, the contents of the file. These selections can be
465 made with the B<--type> option.
466
467 With no file selection, I<ack> searches through regular files that
468 are not explicitly excluded by B<--ignore-dir> and B<--ignore-file>
469 options, either present in F<ackrc> files or on the command line.
470
471 The default options for I<ack> ignore certain files and directories. These
472 include:
473
474 =over 4
475
476 =item * Backup files: Files matching F<#*#> or ending with F<~>.
477
478 =item * Coredumps: Files matching F<core.\d+>
479
480 =item * Version control directories like F<.svn> and F<.git>.
481
482 =back
483
484 Run I<ack> with the C<--dump> option to see what settings are set.
485
486 However, I<ack> always searches the files given on the command line,
487 no matter what type. If you tell I<ack> to search in a coredump,
488 it will search in a coredump.
489
490 =head1 DIRECTORY SELECTION
491
492 I<ack> descends through the directory tree of the starting directories
493 specified. If no directories are specified, the current working directory is
494 used. However, it will ignore the shadow directories used by
495 many version control systems, and the build directories used by the
496 Perl MakeMaker system. You may add or remove a directory from this
497 list with the B<--[no]ignore-dir> option. The option may be repeated
498 to add/remove multiple directories from the ignore list.
499
500 For a complete list of directories that do not get searched, run
501 C<ack --dump>.
502
503 =head1 WHEN TO USE GREP
504
505 I<ack> trumps I<grep> as an everyday tool 99% of the time, but don't
506 throw I<grep> away, because there are times you'll still need it.
507
508 E.g., searching through huge files looking for regexes that can be
509 expressed with I<grep> syntax should be quicker with I<grep>.
510
511 If your script or parent program uses I<grep> C<--quiet> or C<--silent>
512 or needs exit 2 on IO error, use I<grep>.
513
514 =head1 OPTIONS
515
516 =over 4
517
518 =item B<-A I<NUM>>, B<--after-context=I<NUM>>
519
520 Print I<NUM> lines of trailing context after matching lines.
521
522 =item B<-B I<NUM>>, B<--before-context=I<NUM>>
523
524 Print I<NUM> lines of leading context before matching lines.
525
526 =item B<--[no]break>
527
528 Print a break between results from different files. On by default
529 when used interactively.
530
531 =item B<-C [I<NUM>]>, B<--context[=I<NUM>]>
532
533 Print I<NUM> lines (default 2) of context around matching lines.
534
535 =item B<-c>, B<--count>
536
537 Suppress normal output; instead print a count of matching lines for
538 each input file. If B<-l> is in effect, it will only show the
539 number of lines for each file that has lines matching. Without
540 B<-l>, some line counts may be zeroes.
541
542 If combined with B<-h> (B<--no-filename>) ack outputs only one total
543 count.
544
545 =item B<--[no]color>, B<--[no]colour>
546
547 B<--color> highlights the matching text. B<--nocolor> supresses
548 the color. This is on by default unless the output is redirected.
549
550 On Windows, this option is off by default unless the
551 L<Win32::Console::ANSI> module is installed or the C<ACK_PAGER_COLOR>
552 environment variable is used.
553
554 =item B<--color-filename=I<color>>
555
556 Sets the color to be used for filenames.
557
558 =item B<--color-match=I<color>>
559
560 Sets the color to be used for matches.
561
562 =item B<--color-lineno=I<color>>
563
564 Sets the color to be used for line numbers.
565
566 =item B<--[no]column>
567
568 Show the column number of the first match. This is helpful for
569 editors that can place your cursor at a given position.
570
571 =item B<--create-ackrc>
572
573 Dumps the default ack options to standard output. This is useful for
574 when you want to customize the defaults.
575
576 =item B<--dump>
577
578 Writes the list of options loaded and where they came from to standard
579 output. Handy for debugging.
580
581 =item B<--[no]env>
582
583 B<--noenv> disables all environment processing. No F<.ackrc> is
584 read and all environment variables are ignored. By default, F<ack>
585 considers F<.ackrc> and settings in the environment.
586
587 =item B<--flush>
588
589 B<--flush> flushes output immediately. This is off by default
590 unless ack is running interactively (when output goes to a pipe or
591 file).
592
593 =item B<-f>
594
595 Only print the files that would be searched, without actually doing
596 any searching. PATTERN must not be specified, or it will be taken
597 as a path to search.
598
599 =item B<--files-from=I<FILE>>
600
601 The list of files to be searched is specified in I<FILE>. The list of
602 files are seperated by newlines. If I<FILE> is C<->, the list is loaded
603 from standard input.
604
605 =item B<--[no]filter>
606
607 Forces ack to act as if it were recieving input via a pipe.
608
609 =item B<--[no]follow>
610
611 Follow or don't follow symlinks, other than whatever starting files
612 or directories were specified on the command line.
613
614 This is off by default.
615
616 =item B<-g I<PATTERN>>
617
618 Print files where the relative path + filename matches I<PATTERN>.
619
620 =item B<--[no]group>
621
622 B<--group> groups matches by file name. This is the default
623 when used interactively.
624
625 B<--nogroup> prints one result per line, like grep. This is the
626 default when output is redirected.
627
628 =item B<-H>, B<--with-filename>
629
630 Print the filename for each match. This is the default unless searching
631 a single explicitly specified file.
632
633 =item B<-h>, B<--no-filename>
634
635 Suppress the prefixing of filenames on output when multiple files are
636 searched.
637
638 =item B<--[no]heading>
639
640 Print a filename heading above each file's results. This is the default
641 when used interactively.
642
643 =item B<--help>, B<-?>
644
645 Print a short help statement.
646
647 =item B<--help-types>, B<--help=types>
648
649 Print all known types.
650
651 =item B<-i>, B<--ignore-case>
652
653 Ignore case distinctions in PATTERN
654
655 =item B<--ignore-ack-defaults>
656
657 Tells ack to completely ignore the default definitions provided with ack.
658 This is useful in combination with B<--create-ackrc> if you I<really> want
659 to customize ack.
660
661 =item B<--[no]ignore-dir=I<DIRNAME>>, B<--[no]ignore-directory=I<DIRNAME>>
662
663 Ignore directory (as CVS, .svn, etc are ignored). May be used
664 multiple times to ignore multiple directories. For example, mason
665 users may wish to include B<--ignore-dir=data>. The B<--noignore-dir>
666 option allows users to search directories which would normally be
667 ignored (perhaps to research the contents of F<.svn/props> directories).
668
669 The I<DIRNAME> must always be a simple directory name. Nested
670 directories like F<foo/bar> are NOT supported. You would need to
671 specify B<--ignore-dir=foo> and then no files from any foo directory
672 are taken into account by ack unless given explicitly on the command
673 line.
674
675 =item B<--ignore-file=I<FILTERTYPE:FILTERARGS>>
676
677 Ignore files matching I<FILTERTYPE:FILTERARGS>. The filters are specified
678 identically to file type filters as seen in L</"Defining your own types">.
679
680 =item B<-k>, B<--known-types>
681
682 Limit selected files to those with types that ack knows about. This is
683 equivalent to the default behavior found in ack 1.
684
685 =item B<--lines=I<NUM>>
686
687 Only print line I<NUM> of each file. Multiple lines can be given with multiple
688 B<--lines> options or as a comma separated list (B<--lines=3,5,7>). B<--lines=4-7>
689 also works. The lines are always output in ascending order, no matter the
690 order given on the command line.
691
692 =item B<-l>, B<--files-with-matches>
693
694 Only print the filenames of matching files, instead of the matching text.
695
696 =item B<-L>, B<--files-without-matches>
697
698 Only print the filenames of files that do I<NOT> match.
699
700 =item B<--match I<PATTERN>>
701
702 Specify the I<PATTERN> explicitly. This is helpful if you don't want to put the
703 regex as your first argument, e.g. when executing multiple searches over the
704 same set of files.
705
706 # search for foo and bar in given files
707 ack file1 t/file* --match foo
708 ack file1 t/file* --match bar
709
710 =item B<-m=I<NUM>>, B<--max-count=I<NUM>>
711
712 Stop reading a file after I<NUM> matches.
713
714 =item B<--man>
715
716 Print this manual page.
717
718 =item B<-n>, B<--no-recurse>
719
720 No descending into subdirectories.
721
722 =item B<-o>
723
724 Show only the part of each line matching PATTERN (turns off text
725 highlighting)
726
727 =item B<--output=I<expr>>
728
729 Output the evaluation of I<expr> for each line (turns off text
730 highlighting)
731 If PATTERN matches more than once then a line is output for each non-overlapping match.
732 For more information please see the section L</"Examples of F<--output>">.
733
734 =item B<--pager=I<program>>, B<--nopager>
735
736 B<--pager> directs ack's output through I<program>. This can also be specified
737 via the C<ACK_PAGER> and C<ACK_PAGER_COLOR> environment variables.
738
739 Using --pager does not suppress grouping and coloring like piping
740 output on the command-line does.
741
742 B<--nopager> cancels any setting in ~/.ackrc, C<ACK_PAGER> or C<ACK_PAGER_COLOR>.
743 No output will be sent through a pager.
744
745 =item B<--passthru>
746
747 Prints all lines, whether or not they match the expression. Highlighting
748 will still work, though, so it can be used to highlight matches while
749 still seeing the entire file, as in:
750
751 # Watch a log file, and highlight a certain IP address
752 $ tail -f ~/access.log | ack --passthru 123.45.67.89
753
754 =item B<--print0>
755
756 Only works in conjunction with -f, -g, -l or -c (filename output). The filenames
757 are output separated with a null byte instead of the usual newline. This is
758 helpful when dealing with filenames that contain whitespace, e.g.
759
760 # remove all files of type html
761 ack -f --html --print0 | xargs -0 rm -f
762
763 =item B<-Q>, B<--literal>
764
765 Quote all metacharacters in PATTERN, it is treated as a literal.
766
767 =item B<-r>, B<-R>, B<--recurse>
768
769 Recurse into sub-directories. This is the default and just here for
770 compatibility with grep. You can also use it for turning B<--no-recurse> off.
771
772 =item B<-s>
773
774 Suppress error messages about nonexistent or unreadable files. This is taken
775 from fgrep.
776
777 =item B<--[no]smart-case>, B<--no-smart-case>
778
779 Ignore case in the search strings if PATTERN contains no uppercase
780 characters. This is similar to C<smartcase> in vim. This option is
781 off by default, and ignored if C<-i> is specified.
782
783 B<-i> always overrides this option.
784
785 =item B<--sort-files>
786
787 Sorts the found files lexicographically. Use this if you want your file
788 listings to be deterministic between runs of I<ack>.
789
790 =item B<--show-types>
791
792 Outputs the filetypes that ack associates with each file.
793
794 Works with B<-f> and B<-g> options.
795
796 =item B<--type=[no]TYPE>
797
798 Specify the types of files to include or exclude from a search.
799 TYPE is a filetype, like I<perl> or I<xml>. B<--type=perl> can
800 also be specified as B<--perl>, and B<--type=noperl> can be done
801 as B<--noperl>.
802
803 If a file is of both type "foo" and "bar", specifying --foo and
804 --nobar will exclude the file, because an exclusion takes precedence
805 over an inclusion.
806
807 Type specifications can be repeated and are ORed together.
808
809 See I<ack --help=types> for a list of valid types.
810
811 =item B<--type-add I<TYPE>:I<FILTER>:I<FILTERARGS>>
812
813 Files with the given FILTERARGS applied to the given FILTER
814 are recognized as being of (the existing) type TYPE.
815 See also L</"Defining your own types">.
816
817
818 =item B<--type-set I<TYPE>:I<FILTER>:I<FILTERARGS>>
819
820 Files with the given FILTERARGS applied to the given FILTER are recognized as
821 being of type TYPE. This replaces an existing definition for type TYPE. See
822 also L</"Defining your own types">.
823
824 =item B<--type-del I<TYPE>>
825
826 The filters associated with TYPE are removed from Ack, and are no longer considered
827 for searches.
828
829 =item B<-v>, B<--invert-match>
830
831 Invert match: select non-matching lines
832
833 =item B<--version>
834
835 Display version and copyright information.
836
837 =item B<-w>, B<--word-regexp>
838
839 Force PATTERN to match only whole words. The PATTERN is wrapped with
840 C<\b> metacharacters.
841
842 =item B<-x>
843
844 An abbreviation for B<--files-from=->; the list of files to search are read
845 from standard input, with one line per file.
846
847 =item B<-1>
848
849 Stops after reporting first match of any kind. This is different
850 from B<--max-count=1> or B<-m1>, where only one match per file is
851 shown. Also, B<-1> works with B<-f> and B<-g>, where B<-m> does
852 not.
853
854 =item B<--thpppt>
855
856 Display the all-important Bill The Cat logo. Note that the exact
857 spelling of B<--thpppppt> is not important. It's checked against
858 a regular expression.
859
860 =item B<--bar>
861
862 Check with the admiral for traps.
863
864 =back
865
866 =head1 THE .ackrc FILE
867
868 The F<.ackrc> file contains command-line options that are prepended
869 to the command line before processing. Multiple options may live
870 on multiple lines. Lines beginning with a # are ignored. A F<.ackrc>
871 might look like this:
872
873 # Always sort the files
874 --sort-files
875
876 # Always color, even if piping to a another program
877 --color
878
879 # Use "less -r" as my pager
880 --pager=less -r
881
882 Note that arguments with spaces in them do not need to be quoted,
883 as they are not interpreted by the shell. Basically, each I<line>
884 in the F<.ackrc> file is interpreted as one element of C<@ARGV>.
885
886 F<ack> looks in several locations for F<.ackrc> files; the searching
887 process is detailed in L</"ACKRC LOCATION SEMANTICS">. These
888 files are not considered if B<--noenv> is specified on the command line.
889
890 =head1 Defining your own types
891
892 ack allows you to define your own types in addition to the predefined
893 types. This is done with command line options that are best put into
894 an F<.ackrc> file - then you do not have to define your types over and
895 over again. In the following examples the options will always be shown
896 on one command line so that they can be easily copy & pasted.
897
898 I<ack --perl foo> searches for foo in all perl files. I<ack --help=types>
899 tells you, that perl files are files ending
900 in .pl, .pm, .pod or .t. So what if you would like to include .xs
901 files as well when searching for --perl files? I<ack --type-add perl:ext:xs --perl foo>
902 does this for you. B<--type-add> appends
903 additional extensions to an existing type.
904
905 If you want to define a new type, or completely redefine an existing
906 type, then use B<--type-set>. I<ack --type-set eiffel:ext:e,eiffel> defines
907 the type I<eiffel> to include files with
908 the extensions .e or .eiffel. So to search for all eiffel files
909 containing the word Bertrand use I<ack --type-set eiffel:ext:e,eiffel --eiffel Bertrand>.
910 As usual, you can also write B<--type=eiffel>
911 instead of B<--eiffel>. Negation also works, so B<--noeiffel> excludes
912 all eiffel files from a search. Redefining also works: I<ack --type-set cc:ext:c,h>
913 and I<.xs> files no longer belong to the type I<cc>.
914
915 When defining your own types in the F<.ackrc> file you have to use
916 the following:
917
918 --type-set=eiffel:ext:e,eiffel
919
920 or writing on separate lines
921
922 --type-set
923 eiffel:ext:e,eiffel
924
925 The following does B<NOT> work in the F<.ackrc> file:
926
927 --type-set eiffel:ext:e,eiffel
928
929
930 In order to see all currently defined types, use I<--help-types>, e.g.
931 I<ack --type-set backup:ext:bak --type-add perl:ext:perl --help-types>
932
933 In addition to filtering based on extension (like ack 1.x allowed), ack 2
934 offers additional filter types. The generic syntax is
935 I<--type-set TYPE:FILTER:FILTERARGS>; I<FILTERARGS> depends on the value
936 of I<FILTER>.
937
938 =over 4
939
940 =item is:I<FILENAME>
941
942 I<is> filters match the target filename exactly. It takes exactly one
943 argument, which is the name of the file to match.
944
945 Example:
946
947 --type-set make:is:Makefile
948
949 =item ext:I<EXTENSION>[,I<EXTENSION2>[,...]]
950
951 I<ext> filters match the extension of the target file against a list
952 of extensions. No leading dot is needed for the extensions.
953
954 Example:
955
956 --type-set perl:ext:pl,pm,t
957
958 =item match:I<PATTERN>
959
960 I<match> filters match the target filename against a regular expression.
961 The regular expression is made case insensitive for the search.
962
963 Example:
964
965 --type-set make:match:/(gnu)?makefile/
966
967 =item firstlinematch:I<PATTERN>
968
969 I<firstlinematch> matches the first line of the target file against a
970 regular expression. Like I<match>, the regular expression is made
971 case insensitive.
972
973 Example:
974
975 --type-add perl:firstlinematch:/perl/
976
977 =back
978
979 More filter types may be made available in the future.
980
981 =head1 ENVIRONMENT VARIABLES
982
983 For commonly-used ack options, environment variables can make life
984 much easier. These variables are ignored if B<--noenv> is specified
985 on the command line.
986
987 =over 4
988
989 =item ACKRC
990
991 Specifies the location of the user's F<.ackrc> file. If this file doesn't
992 exist, F<ack> looks in the default location.
993
994 =item ACK_OPTIONS
995
996 This variable specifies default options to be placed in front of
997 any explicit options on the command line.
998
999 =item ACK_COLOR_FILENAME
1000
1001 Specifies the color of the filename when it's printed in B<--group>
1002 mode. By default, it's "bold green".
1003
1004 The recognized attributes are clear, reset, dark, bold, underline,
1005 underscore, blink, reverse, concealed black, red, green, yellow,
1006 blue, magenta, on_black, on_red, on_green, on_yellow, on_blue,
1007 on_magenta, on_cyan, and on_white. Case is not significant.
1008 Underline and underscore are equivalent, as are clear and reset.
1009 The color alone sets the foreground color, and on_color sets the
1010 background color.
1011
1012 This option can also be set with B<--color-filename>.
1013
1014 =item ACK_COLOR_MATCH
1015
1016 Specifies the color of the matching text when printed in B<--color>
1017 mode. By default, it's "black on_yellow".
1018
1019 This option can also be set with B<--color-match>.
1020
1021 See B<ACK_COLOR_FILENAME> for the color specifications.
1022
1023 =item ACK_COLOR_LINENO
1024
1025 Specifies the color of the line number when printed in B<--color>
1026 mode. By default, it's "bold yellow".
1027
1028 This option can also be set with B<--color-lineno>.
1029
1030 See B<ACK_COLOR_FILENAME> for the color specifications.
1031
1032 =item ACK_PAGER
1033
1034 Specifies a pager program, such as C<more>, C<less> or C<most>, to which
1035 ack will send its output.
1036
1037 Using C<ACK_PAGER> does not suppress grouping and coloring like
1038 piping output on the command-line does, except that on Windows
1039 ack will assume that C<ACK_PAGER> does not support color.
1040
1041 C<ACK_PAGER_COLOR> overrides C<ACK_PAGER> if both are specified.
1042
1043 =item ACK_PAGER_COLOR
1044
1045 Specifies a pager program that understands ANSI color sequences.
1046 Using C<ACK_PAGER_COLOR> does not suppress grouping and coloring
1047 like piping output on the command-line does.
1048
1049 If you are not on Windows, you never need to use C<ACK_PAGER_COLOR>.
1050
1051 =back
1052
1053 =head1 ACK & OTHER TOOLS
1054
1055 =head2 Vim integration
1056
1057 F<ack> integrates easily with the Vim text editor. Set this in your
1058 F<.vimrc> to use F<ack> instead of F<grep>:
1059
1060 set grepprg=ack\ -k
1061
1062 That example uses C<-k> to search through only files of the types ack
1063 knows about, but you may use other default flags. Now you can search
1064 with F<ack> and easily step through the results in Vim:
1065
1066 :grep Dumper perllib
1067
1068 Miles Sterrett has written a Vim plugin for F<ack> which allows you to use
1069 C<:Ack> instead of C<:grep>, as well as several other advanced features.
1070
1071 L<https://github.com/mileszs/ack.vim>
1072
1073 =head2 Emacs integration
1074
1075 Phil Jackson put together an F<ack.el> extension that "provides a
1076 simple compilation mode ... has the ability to guess what files you
1077 want to search for based on the major-mode."
1078
1079 L<http://www.shellarchive.co.uk/content/emacs.html>
1080
1081 =head2 TextMate integration
1082
1083 Pedro Melo is a TextMate user who writes "I spend my day mostly
1084 inside TextMate, and the built-in find-in-project sucks with large
1085 projects. So I hacked a TextMate command that was using find +
1086 grep to use ack. The result is the Search in Project with ack, and
1087 you can find it here:
1088 L<http://www.simplicidade.org/notes/archives/2008/03/search_in_proje.html>"
1089
1090 =head2 Shell and Return Code
1091
1092 For greater compatibility with I<grep>, I<ack> in normal use returns
1093 shell return or exit code of 0 only if something is found and 1 if
1094 no match is found.
1095
1096 (Shell exit code 1 is C<$?=256> in perl with C<system> or backticks.)
1097
1098 The I<grep> code 2 for errors is not used.
1099
1100 If C<-f> or C<-g> are specified, then 0 is returned if at least one
1101 file is found. If no files are found, then 1 is returned.
1102
1103 =cut
1104
1105 =head1 DEBUGGING ACK PROBLEMS
1106
1107 If ack gives you output you're not expecting, start with a few simple steps.
1108
1109 =head2 Use B<--noenv>
1110
1111 Your environment variables and F<.ackrc> may be doing things you're
1112 not expecting, or forgotten you specified. Use B<--noenv> to ignore
1113 your environment and F<.ackrc>.
1114
1115 =head2 Use B<-f> to see what files have been selected
1116
1117 Ack's B<-f> was originally added as a debugging tool. If ack is
1118 not finding matches you think it should find, run F<ack -f> to see
1119 what files have been selected. You can also add the C<--show-types>
1120 options to show the type of each file selected.
1121
1122 =head2 Use B<--dump>
1123
1124 This lists the ackrc files that are loaded and the options loaded
1125 from them.
1126 So for example you can find a list of directories that do not get searched or where filetypes are defined.
1127
1128 =head1 TIPS
1129
1130 =head2 Use the F<.ackrc> file.
1131
1132 The F<.ackrc> is the place to put all your options you use most of
1133 the time but don't want to remember. Put all your --type-add and
1134 --type-set definitions in it. If you like --smart-case, set it
1135 there, too. I also set --sort-files there.
1136
1137 =head2 Use F<-f> for working with big codesets
1138
1139 Ack does more than search files. C<ack -f --perl> will create a
1140 list of all the Perl files in a tree, ideal for sending into F<xargs>.
1141 For example:
1142
1143 # Change all "this" to "that" in all Perl files in a tree.
1144 ack -f --perl | xargs perl -p -i -e's/this/that/g'
1145
1146 or if you prefer:
1147
1148 perl -p -i -e's/this/that/g' $(ack -f --perl)
1149
1150 =head2 Use F<-Q> when in doubt about metacharacters
1151
1152 If you're searching for something with a regular expression
1153 metacharacter, most often a period in a filename or IP address, add
1154 the -Q to avoid false positives without all the backslashing. See
1155 the following example for more...
1156
1157 =head2 Use ack to watch log files
1158
1159 Here's one I used the other day to find trouble spots for a website
1160 visitor. The user had a problem loading F<troublesome.gif>, so I
1161 took the access log and scanned it with ack twice.
1162
1163 ack -Q aa.bb.cc.dd /path/to/access.log | ack -Q -B5 troublesome.gif
1164
1165 The first ack finds only the lines in the Apache log for the given
1166 IP. The second finds the match on my troublesome GIF, and shows
1167 the previous five lines from the log in each case.
1168
1169 =head2 Examples of F<--output>
1170
1171 Following variables are useful in the expansion string:
1172
1173 =over 4
1174
1175 =item C<$&>
1176
1177 The whole string matched by PATTERN.
1178
1179 =item C<$1>, C<$2>, ...
1180
1181 The contents of the 1st, 2nd ... bracketed group in PATTERN.
1182
1183 =item C<$`>
1184
1185 The string before the match.
1186
1187 =item C<$'>
1188
1189 The string after the match.
1190
1191 =back
1192
1193 For more details and other variables see
1194 L<http://perldoc.perl.org/perlvar.html#Variables-related-to-regular-expressions|perlvar>.
1195
1196 This example shows how to add text around a particular pattern
1197 (in this case adding _ around word with "e")
1198
1199 ack2.pl "\w*e\w*" quick.txt --output="$`_$&_$'"
1200 _The_ quick brown fox jumps over the lazy dog
1201 The quick brown fox jumps _over_ the lazy dog
1202 The quick brown fox jumps over _the_ lazy dog
1203
1204 This shows how to pick out particular parts of a match using ( ) within regular expression.
1205
1206 ack '=head(\d+)\s+(.*)' --output=' $1 : $2'
1207 input file contains "=head1 NAME"
1208 output "1 : NAME"
1209
1210 =head2 Share your knowledge
1211
1212 Join the ack-users mailing list. Send me your tips and I may add
1213 them here.
1214
1215 =head1 FAQ
1216
1217 =head2 Why isn't ack finding a match in (some file)?
1218
1219 Probably because it's of a type that ack doesn't recognize. ack's
1220 searching behavior is driven by filetype. B<If ack doesn't know
1221 what kind of file it is, ack ignores the file.>
1222
1223 Use the C<-f> switch to see a list of files that ack will search
1224 for you.
1225
1226 If you want ack to search files that it doesn't recognize, use the
1227 C<-a> switch.
1228
1229 If you want ack to search every file, even ones that it always
1230 ignores like coredumps and backup files, use the C<-u> switch.
1231
1232 =head2 Why does ack ignore unknown files by default?
1233
1234 ack is designed by a programmer, for programmers, for searching
1235 large trees of code. Most codebases have a lot files in them which
1236 aren't source files (like compiled object files, source control
1237 metadata, etc), and grep wastes a lot of time searching through all
1238 of those as well and returning matches from those files.
1239
1240 That's why ack's behavior of not searching things it doesn't recognize
1241 is one of its greatest strengths: the speed you get from only
1242 searching the things that you want to be looking at.
1243
1244 =head2 Wouldn't it be great if F<ack> did search & replace?
1245
1246 No, ack will always be read-only. Perl has a perfectly good way
1247 to do search & replace in files, using the C<-i>, C<-p> and C<-n>
1248 switches.
1249
1250 You can certainly use ack to select your files to update. For
1251 example, to change all "foo" to "bar" in all PHP files, you can do
1252 this from the Unix shell:
1253
1254 $ perl -i -p -e's/foo/bar/g' $(ack -f --php)
1255
1256 =head2 Can you make ack recognize F<.xyz> files?
1257
1258 Yes! Please see L</"Defining your own types">. If you think
1259 that F<ack> should recognize a type by default, please see
1260 L</"ENHANCEMENTS">.
1261
1262 =head2 There's already a program/package called ack.
1263
1264 Yes, I know.
1265
1266 =head2 Why is it called ack if it's called ack-grep?
1267
1268 The name of the program is "ack". Some packagers have called it
1269 "ack-grep" when creating packages because there's already a package
1270 out there called "ack" that has nothing to do with this ack.
1271
1272 I suggest you make a symlink named F<ack> that points to F<ack-grep>
1273 because one of the crucial benefits of ack is having a name that's
1274 so short and simple to type.
1275
1276 To do that, run this with F<sudo> or as root:
1277
1278 ln -s /usr/bin/ack-grep /usr/bin/ack
1279
1280 Alternatively, you could use a shell alias:
1281
1282 # bash/zsh
1283 alias ack=ack-grep
1284
1285 # csh
1286 alias ack ack-grep
1287
1288 =head2 What does F<ack> mean?
1289
1290 Nothing. I wanted a name that was easy to type and that you could
1291 pronounce as a single syllable.
1292
1293 =head2 Can I do multi-line regexes?
1294
1295 No, ack does not support regexes that match multiple lines. Doing
1296 so would require reading in the entire file at a time.
1297
1298 If you want to see lines near your match, use the C<--A>, C<--B>
1299 and C<--C> switches for displaying context.
1300
1301 =head2 Why is ack telling me I have an invalid option when searching for C<+foo>?
1302
1303 ack treats command line options beginning with C<+> or C<-> as options; if you
1304 would like to search for these, you may prefix your search term with C<--> or
1305 use the C<--match> option. (However, don't forget that C<+> is a regular
1306 expression metacharacter!)
1307
1308 =head1 ACKRC LOCATION SEMANTICS
1309
1310 Ack can load its configuration from many sources. This list
1311 specifies the sources Ack looks for configuration; each one
1312 that is found is loaded in the order specified here, and
1313 each one overrides options set in any of the sources preceding
1314 it. (For example, if I set --sort-files in my user ackrc, and
1315 --nosort-files on the command line, the command line takes
1316 precedence)
1317
1318 =over 4
1319
1320 =item *
1321
1322 Defaults are loaded from App::Ack::ConfigDefaults. This can be omitted
1323 using C<--ignore-ack-defaults>.
1324
1325 =item * Global ackrc
1326
1327 Options are then loaded from the global ackrc. This is located at
1328 C</etc/ackrc> on Unix-like systems, and
1329 C<C:\Documents and Settings\All Users\Application Data> on Windows.
1330 This can be omitted using C<--noenv>.
1331
1332 =item * User ackrc
1333
1334 Options are then loaded from the user's ackrc. This is located at
1335 C<$HOME/.ackrc> on Unix-like systems, and
1336 C<C:\Documents and Settings\$USER\Application Data>. If a different
1337 ackrc is desired, it may be overriden with the C<$ACKRC> environment
1338 variable.
1339 This can be omitted using C<--noenv>.
1340
1341 =item * Project ackrc
1342
1343 Options are then loaded from the project ackrc. The project ackrc is
1344 the first ackrc file with the name C<.ackrc> or C<_ackrc>, first searching
1345 in the current directory, then the parent directory, then the grandparent
1346 directory, etc. This can be omitted using C<--noenv>.
1347
1348 =item * ACK_OPTIONS
1349
1350 Options are then loaded from the enviroment variable C<ACK_OPTIONS>. This can
1351 be omitted using C<--noenv>.
1352
1353 =item * Command line
1354
1355 Options are then loaded from the command line.
1356
1357 =back
1358
1359 =head1 DIFFERENCES BETWEEN ACK 1.X AND ACK 2.X
1360
1361 A lot of changes were made for ack 2; here is a list of them.
1362
1363 =head2 GENERAL CHANGES
1364
1365 =over 4
1366
1367 =item *
1368
1369 When no selectors are specified, ack 1.x only searches through files that
1370 it can map to a file type. ack 2.x, by constrast, will search through
1371 every regular, non-binary file that is not explicitly ignored via
1372 B<--ignore-file> or B<--ignore-dir>. This is similar to the behavior of the
1373 B<-a/--all> option in ack 1.x.
1374
1375 =item *
1376
1377 A more flexible filter system has been added, so that more powerful file types
1378 may be created by the user. For details, please consult
1379 L</"Defining your own types">.
1380
1381 =item *
1382
1383 ack now loads multiple ackrc files; see L</"ACKRC LOCATION SEMANTICS"> for
1384 details.
1385
1386 =item *
1387
1388 ack's default filter definitions aren't special; you may tell ack to
1389 completely disregard them if you don't like them.
1390
1391 =back
1392
1393 =head2 REMOVED OPTIONS
1394
1395 =over 4
1396
1397 =item *
1398
1399 Because of the change in default search behavior, the B<-a/--all> and
1400 B<-u/--unrestricted> options have been removed. In addition, the
1401 B<-k/--known-types> option was added to cause ack to behave with
1402 the default search behavior of ack 1.x.
1403
1404 =item *
1405
1406 The B<-G> option has been removed. Two regular expressions on the
1407 command line was considered too confusing; to simulate B<-G>'s functionality,
1408 you may use the new B<-x> option to pipe filenames from one invocation of
1409 ack into another.
1410
1411 =item *
1412
1413 The B<--binary> option has been removed.
1414
1415 =item *
1416
1417 The B<--skipped> option has been removed.
1418
1419 =item *
1420
1421 The B<--text> option has been removed.
1422
1423 =item *
1424
1425 The B<--invert-file-match> option has been removed. Instead, you may
1426 use B<-v> with B<-g>.
1427
1428 =back
1429
1430 =head2 CHANGED OPTIONS
1431
1432 =over 4
1433
1434 =item *
1435
1436 The options that modify the regular expression's behavior (B<-i>, B<-w>,
1437 B<-Q>, and B<-v>) may now be used with B<-g>.
1438
1439 =back
1440
1441 =head2 ADDED OPTIONS
1442
1443 =over 4
1444
1445 =item *
1446
1447 B<--files-from> was added so that a user may submit a list of filenames as
1448 a list of files to search.
1449
1450 =item *
1451
1452 B<-x> was added to tell ack to accept a list of filenames via standard input;
1453 this list is the list of filenames that will be used for the search.
1454
1455 =item *
1456
1457 B<-s> was added to tell ack to suppress error messages about non-existent or
1458 unreadable files.
1459
1460 =item *
1461
1462 B<--ignore-directory> and B<--noignore-directory> were added as aliases for
1463 B<--ignore-dir> and B<--noignore-dir> respectively.
1464
1465 =item *
1466
1467 B<--ignore-file> was added so that users may specify patterns of files to
1468 ignore (ex. /.*~$/).
1469
1470 =item *
1471
1472 B<--dump> was added to allow users to easily find out which options are
1473 set where.
1474
1475 =item *
1476
1477 B<--create-ackrc> was added so that users may create custom ackrc files based
1478 on the default settings loaded by ack, and so that users may easily view those
1479 defaults.
1480
1481 =item *
1482
1483 B<--type-del> was added to selectively remove file type definitions.
1484
1485 =item *
1486
1487 B<--ignore-ack-defaults> was added so that users may ignore ack's default
1488 options in favor of their own.
1489
1490 =item *
1491
1492 B<--bar> was added so ack users may consult Admiral Ackbar.
1493
1494 =back
1495
1496 =head1 AUTHOR
1497
1498 Andy Lester, C<< <andy at petdance.com> >>
1499
1500 =head1 BUGS
1501
1502 Please report any bugs or feature requests to the issues list at
1503 Github: L<https://github.com/petdance/ack2/issues>
1504
1505 =head1 ENHANCEMENTS
1506
1507 All enhancement requests MUST first be posted to the ack-users
1508 mailing list at L<http://groups.google.com/group/ack-users>. I
1509 will not consider a request without it first getting seen by other
1510 ack users. This includes requests for new filetypes.
1511
1512 There is a list of enhancements I want to make to F<ack> in the ack
1513 issues list at Github: L<https://github.com/petdance/ack2/issues>
1514
1515 Patches are always welcome, but patches with tests get the most
1516 attention.
1517
1518 =head1 SUPPORT
1519
1520 Support for and information about F<ack> can be found at:
1521
1522 =over 4
1523
1524 =item * The ack homepage
1525
1526 L<http://beyondgrep.com/>
1527
1528 =item * The ack-users mailing list
1529
1530 L<http://groups.google.com/group/ack-users>
1531
1532 =item * The ack issues list at Github
1533
1534 L<https://github.com/petdance/ack2/issues>
1535
1536 =item * AnnoCPAN: Annotated CPAN documentation
1537
1538 L<http://annocpan.org/dist/ack>
1539
1540 =item * CPAN Ratings
1541
1542 L<http://cpanratings.perl.org/d/ack>
1543
1544 =item * Search CPAN
1545
1546 L<http://search.cpan.org/dist/ack>
1547
1548 =item * Git source repository
1549
1550 L<https://github.com/petdance/ack2>
1551
1552 =back
1553
1554 =head1 ACKNOWLEDGEMENTS
1555
1556 How appropriate to have I<ack>nowledgements!
1557
1558 Thanks to everyone who has contributed to ack in any way, including
1559 Michael McClimon,
1560 Andrew Black,
1561 Ralph Bodenner,
1562 Shaun Patterson,
1563 Ryan Olson,
1564 Shlomi Fish,
1565 Karen Etheridge,
1566 Olivier Mengue,
1567 Matthew Wild,
1568 Scott Kyle,
1569 Nick Hooey,
1570 Bo Borgerson,
1571 Mark Szymanski,
1572 Marq Schneider,
1573 Packy Anderson,
1574 JR Boyens,
1575 Dan Sully,
1576 Ryan Niebur,
1577 Kent Fredric,
1578 Mike Morearty,
1579 Ingmar Vanhassel,
1580 Eric Van Dewoestine,
1581 Sitaram Chamarty,
1582 Adam James,
1583 Richard Carlsson,
1584 Pedro Melo,
1585 AJ Schuster,
1586 Phil Jackson,
1587 Michael Schwern,
1588 Jan Dubois,
1589 Christopher J. Madsen,
1590 Matthew Wickline,
1591 David Dyck,
1592 Jason Porritt,
1593 Jjgod Jiang,
1594 Thomas Klausner,
1595 Uri Guttman,
1596 Peter Lewis,
1597 Kevin Riggle,
1598 Ori Avtalion,
1599 Torsten Blix,
1600 Nigel Metheringham,
1601 GE<aacute>bor SzabE<oacute>,
1602 Tod Hagan,
1603 Michael Hendricks,
1604 E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason,
1605 Piers Cawley,
1606 Stephen Steneker,
1607 Elias Lutfallah,
1608 Mark Leighton Fisher,
1609 Matt Diephouse,
1610 Christian Jaeger,
1611 Bill Sully,
1612 Bill Ricker,
1613 David Golden,
1614 Nilson Santos F. Jr,
1615 Elliot Shank,
1616 Merijn Broeren,
1617 Uwe Voelker,
1618 Rick Scott,
1619 Ask BjE<oslash>rn Hansen,
1620 Jerry Gay,
1621 Will Coleda,
1622 Mike O'Regan,
1623 Slaven ReziE<0x107>,
1624 Mark Stosberg,
1625 David Alan Pisoni,
1626 Adriano Ferreira,
1627 James Keenan,
1628 Leland Johnson,
1629 Ricardo Signes,
1630 Pete Krawczyk and
1631 Rob Hoelz.
1632
1633 =head1 COPYRIGHT & LICENSE
1634
1635 Copyright 2005-2013 Andy Lester.
1636
1637 This program is free software; you can redistribute it and/or modify
1638 it under the terms of the Artistic License v2.0.
1639
1640 See http://www.perlfoundation.org/artistic_license_2_0 or the LICENSE.md
1641 file that comes with the ack distribution.
1642
1643 =cut
1644 package File::Next;
1645
1646 use strict;
1647 use warnings;
1648
1649
1650 our $VERSION = '1.12';
1651
1652
1653
1654 use File::Spec ();
1655
1656 our $name; # name of the current file
1657 our $dir; # dir of the current file
1658
1659 our %files_defaults;
1660 our %skip_dirs;
1661
1662 BEGIN {
1663 %files_defaults = (
1664 file_filter => undef,
1665 descend_filter => undef,
1666 error_handler => sub { CORE::die @_ },
1667 warning_handler => sub { CORE::warn @_ },
1668 sort_files => undef,
1669 follow_symlinks => 1,
1670 nul_separated => 0,
1671 );
1672 %skip_dirs = map {($_,1)} (File::Spec->curdir, File::Spec->updir);
1673 }
1674
1675
1676 sub files {
1677 die _bad_invocation() if @_ && defined($_[0]) && ($_[0] eq __PACKAGE__);
1678
1679 my ($parms,@queue) = _setup( \%files_defaults, @_ );
1680 my $filter = $parms->{file_filter};
1681
1682 return sub {
1683 while (@queue) {
1684 my ($dirname,$file,$fullpath) = splice( @queue, 0, 3 );
1685 if ( -f $fullpath || -p $fullpath || $fullpath =~ m{^/dev/fd} ) {
1686 if ( $filter ) {
1687 local $_ = $file;
1688 local $File::Next::dir = $dirname;
1689 local $File::Next::name = $fullpath;
1690 next if not $filter->();
1691 }
1692 return wantarray ? ($dirname,$file,$fullpath) : $fullpath;
1693 }
1694 elsif ( -d _ ) {
1695 unshift( @queue, _candidate_files( $parms, $fullpath ) );
1696 }
1697 } # while
1698
1699 return;
1700 }; # iterator
1701 }
1702
1703
1704
1705
1706
1707
1708 sub from_file {
1709 die _bad_invocation() if @_ && defined($_[0]) && ($_[0] eq __PACKAGE__);
1710
1711 my ($parms,@queue) = _setup( \%files_defaults, @_ );
1712 my $err = $parms->{error_handler};
1713 my $warn = $parms->{error_handler};
1714
1715 my $filename = $queue[1];
1716
1717 if ( !defined($filename) ) {
1718 $err->( 'Must pass a filename to from_file()' );
1719 return undef;
1720 }
1721
1722 my $fh;
1723 if ( $filename eq '-' ) {
1724 $fh = \*STDIN;
1725 }
1726 else {
1727 if ( !open( $fh, '<', $filename ) ) {
1728 $err->( "Unable to open $filename: $!" );
1729 return undef;
1730 }
1731 }
1732 my $filter = $parms->{file_filter};
1733
1734 return sub {
1735 local $/ = $parms->{nul_separated} ? "\x00" : $/;
1736 while ( my $fullpath = <$fh> ) {
1737 chomp $fullpath;
1738 next unless $fullpath =~ /./;
1739 if ( not ( -f $fullpath || -p _ ) ) {
1740 $warn->( "$fullpath: No such file" );
1741 next;
1742 }
1743
1744 my ($volume,$dirname,$file) = File::Spec->splitpath( $fullpath );
1745 if ( $filter ) {
1746 local $_ = $file;
1747 local $File::Next::dir = $dirname;
1748 local $File::Next::name = $fullpath;
1749 next if not $filter->();
1750 }
1751 return wantarray ? ($dirname,$file,$fullpath) : $fullpath;
1752 } # while
1753 close $fh;
1754
1755 return;
1756 }; # iterator
1757 }
1758
1759 sub _bad_invocation {
1760 my $good = (caller(1))[3];
1761 my $bad = $good;
1762 $bad =~ s/(.+)::/$1->/;
1763 return "$good must not be invoked as $bad";
1764 }
1765
1766 sub sort_standard($$) { return $_[0]->[1] cmp $_[1]->[1] }
1767 sub sort_reverse($$) { return $_[1]->[1] cmp $_[0]->[1] }
1768
1769 sub reslash {
1770 my $path = shift;
1771
1772 my @parts = split( /\//, $path );
1773
1774 return $path if @parts < 2;
1775
1776 return File::Spec->catfile( @parts );
1777 }
1778
1779
1780
1781 sub _setup {
1782 my $defaults = shift;
1783 my $passed_parms = ref $_[0] eq 'HASH' ? {%{+shift}} : {}; # copy parm hash
1784
1785 my %passed_parms = %{$passed_parms};
1786
1787 my $parms = {};
1788 for my $key ( keys %{$defaults} ) {
1789 $parms->{$key} =
1790 exists $passed_parms{$key}
1791 ? delete $passed_parms{$key}
1792 : $defaults->{$key};
1793 }
1794
1795 # Any leftover keys are bogus
1796 for my $badkey ( keys %passed_parms ) {
1797 my $sub = (caller(1))[3];
1798 $parms->{error_handler}->( "Invalid option passed to $sub(): $badkey" );
1799 }
1800
1801 # If it's not a code ref, assume standard sort
1802 if ( $parms->{sort_files} && ( ref($parms->{sort_files}) ne 'CODE' ) ) {
1803 $parms->{sort_files} = \&sort_standard;
1804 }
1805 my @queue;
1806
1807 for ( @_ ) {
1808 my $start = reslash( $_ );
1809 if (-d $start) {
1810 push @queue, ($start,undef,$start);
1811 }
1812 else {
1813 push @queue, (undef,$start,$start);
1814 }
1815 }
1816
1817 return ($parms,@queue);
1818 }
1819
1820
1821 sub _candidate_files {
1822 my $parms = shift;
1823 my $dirname = shift;
1824
1825 my $dh;
1826 if ( !opendir $dh, $dirname ) {
1827 $parms->{error_handler}->( "$dirname: $!" );
1828 return;
1829 }
1830
1831 my @newfiles;
1832 my $descend_filter = $parms->{descend_filter};
1833 my $follow_symlinks = $parms->{follow_symlinks};
1834 my $sort_sub = $parms->{sort_files};
1835
1836 for my $file ( grep { !exists $skip_dirs{$_} } readdir $dh ) {
1837 my $has_stat;
1838
1839 # Only do directory checking if we have a descend_filter
1840 my $fullpath = File::Spec->catdir( $dirname, $file );
1841 if ( !$follow_symlinks ) {
1842 next if -l $fullpath;
1843 $has_stat = 1;
1844 }
1845
1846 if ( $descend_filter ) {
1847 if ( $has_stat ? (-d _) : (-d $fullpath) ) {
1848 local $File::Next::dir = $fullpath;
1849 local $_ = $file;
1850 next if not $descend_filter->();
1851 }
1852 }
1853 if ( $sort_sub ) {
1854 push( @newfiles, [ $dirname, $file, $fullpath ] );
1855 }
1856 else {
1857 push( @newfiles, $dirname, $file, $fullpath );
1858 }
1859 }
1860 closedir $dh;
1861
1862 if ( $sort_sub ) {
1863 return map { @{$_} } sort $sort_sub @newfiles;
1864 }
1865
1866 return @newfiles;
1867 }
1868
1869
1870 1; # End of File::Next
1871 package App::Ack;
1872
1873 use warnings;
1874 use strict;
1875
1876 use Getopt::Long 2.36 ();
1877
1878
1879 our $VERSION;
1880 our $GIT_REVISION;
1881 our $COPYRIGHT;
1882 BEGIN {
1883 $VERSION = '2.02';
1884 $COPYRIGHT = 'Copyright 2005-2013 Andy Lester.';
1885 $GIT_REVISION = q{f3c8827};
1886 }
1887
1888 our $fh;
1889
1890 BEGIN {
1891 $fh = *STDOUT;
1892 }
1893
1894
1895 our %types;
1896 our %type_wanted;
1897 our %mappings;
1898 our %ignore_dirs;
1899
1900 our $is_filter_mode;
1901 our $output_to_pipe;
1902
1903 our $dir_sep_chars;
1904 our $is_cygwin;
1905 our $is_windows;
1906
1907 use File::Spec 1.00015 ();
1908 use File::Glob 1.00015 ':glob';
1909
1910 BEGIN {
1911 # These have to be checked before any filehandle diddling.
1912 $output_to_pipe = not -t *STDOUT;
1913 $is_filter_mode = -p STDIN;
1914
1915 $is_cygwin = ($^O eq 'cygwin');
1916 $is_windows = ($^O =~ /MSWin32/);
1917 $dir_sep_chars = $is_windows ? quotemeta( '\\/' ) : quotemeta( File::Spec->catfile( '', '' ) );
1918 }
1919
1920
1921 sub retrieve_arg_sources {
1922 my @arg_sources;
1923
1924 my $noenv;
1925 my $ackrc;
1926
1927 Getopt::Long::Configure('default', 'no_auto_help', 'no_auto_version');
1928 Getopt::Long::Configure('pass_through');
1929 Getopt::Long::Configure('no_auto_abbrev');
1930
1931 Getopt::Long::GetOptions(
1932 'noenv' => \$noenv,
1933 'ackrc=s' => \$ackrc,
1934 );
1935
1936 Getopt::Long::Configure('default', 'no_auto_help', 'no_auto_version');
1937
1938 my @files;
1939
1940 if ( !$noenv ) {
1941 my $finder = App::Ack::ConfigFinder->new;
1942 @files = $finder->find_config_files;
1943 }
1944 if ( $ackrc ) {
1945 # we explicitly use open so we get a nice error message
1946 # XXX this is a potential race condition!
1947 if(open my $fh, '<', $ackrc) {
1948 close $fh;
1949 }
1950 else {
1951 die "Unable to load ackrc '$ackrc': $!"
1952 }
1953 push( @files, $ackrc );
1954 }
1955
1956 push @arg_sources, Defaults => [ App::Ack::ConfigDefault::options() ];
1957
1958 foreach my $file ( @files) {
1959 my @lines = read_rcfile($file);
1960 push ( @arg_sources, $file, \@lines ) if @lines;
1961 }
1962
1963 if ( $ENV{ACK_OPTIONS} && !$noenv ) {
1964 push( @arg_sources, 'ACK_OPTIONS' => $ENV{ACK_OPTIONS} );
1965 }
1966
1967 push( @arg_sources, 'ARGV' => [ @ARGV ] );
1968
1969 return @arg_sources;
1970 }
1971
1972 sub read_rcfile {
1973 my $file = shift;
1974
1975 return unless defined $file && -e $file;
1976
1977 my @lines;
1978
1979 open( my $fh, '<', $file ) or App::Ack::die( "Unable to read $file: $!" );
1980 while ( my $line = <$fh> ) {
1981 chomp $line;
1982 $line =~ s/^\s+//;
1983 $line =~ s/\s+$//;
1984
1985 next if $line eq '';
1986 next if $line =~ /^#/;
1987
1988 push( @lines, $line );
1989 }
1990 close $fh;
1991
1992 return @lines;
1993 }
1994
1995
1996 sub create_ignore_rules {
1997 my $what = shift;
1998 my $where = shift;
1999 my $opts = shift;
2000
2001 my @opts = @{$opts};
2002
2003 my %rules;
2004
2005 for my $opt ( @opts ) {
2006 if ( $opt =~ /^(is|ext|regex),(.+)$/ ) {
2007 my $method = $1;
2008 my $arg = $2;
2009 if ( $method eq 'regex' ) {
2010 push( @{$rules{regex}}, qr/$arg/ );
2011 }
2012 else {
2013 ++$rules{$method}{$arg};
2014 }
2015 }
2016 else {
2017 App::Ack::die( "Invalid argument for --$what: $opt" );
2018 }
2019 }
2020
2021 return \%rules;
2022 }
2023
2024
2025 sub remove_dir_sep {
2026 my $path = shift;
2027 $path =~ s/[$dir_sep_chars]$//;
2028
2029 return $path;
2030 }
2031
2032
2033 sub build_regex {
2034 my $str = shift;
2035 my $opt = shift;
2036
2037 defined $str or App::Ack::die( 'No regular expression found.' );
2038
2039 $str = quotemeta( $str ) if $opt->{Q};
2040 if ( $opt->{w} ) {
2041 $str = "\\b$str" if $str =~ /^\w/;
2042 $str = "$str\\b" if $str =~ /\w$/;
2043 }
2044
2045 my $regex_is_lc = $str eq lc $str;
2046 if ( $opt->{i} || ($opt->{smart_case} && $regex_is_lc) ) {
2047 $str = "(?i)$str";
2048 }
2049
2050 my $ok = eval {
2051 qr/$str/
2052 };
2053
2054 my $error = $@;
2055
2056 if ( !$ok ) {
2057 die "Invalid regex '$str':\n $error";
2058 }
2059
2060 return $str;
2061 }
2062
2063
2064 sub check_regex {
2065 my $regex = shift;
2066
2067 return unless defined $regex;
2068
2069 eval { qr/$regex/ };
2070 if ($@) {
2071 (my $error = $@) =~ s/ at \S+ line \d+.*//;
2072 chomp($error);
2073 App::Ack::die( "Invalid regex '$regex':\n $error" );
2074 }
2075
2076 return;
2077 }
2078
2079
2080
2081
2082 sub warn {
2083 return CORE::warn( _my_program(), ': ', @_, "\n" );
2084 }
2085
2086
2087 sub die {
2088 return CORE::die( _my_program(), ': ', @_, "\n" );
2089 }
2090
2091 sub _my_program {
2092 require File::Basename;
2093 return File::Basename::basename( $0 );
2094 }
2095
2096
2097
2098 sub filetypes_supported {
2099 return keys %mappings;
2100 }
2101
2102 sub _get_thpppt {
2103 my $y = q{_ /|,\\'!.x',=(www)=, U };
2104 $y =~ tr/,x!w/\nOo_/;
2105 return $y;
2106 }
2107
2108 sub _thpppt {
2109 my $y = _get_thpppt();
2110 App::Ack::print( "$y ack $_[0]!\n" );
2111 exit 0;
2112 }
2113
2114 sub _bar {
2115 my $x;
2116 $x = <<'_BAR';
2117 6?!I'7!I"?%+!
2118 3~!I#7#I"7#I!?!+!="+"="+!:!
2119 2?#I!7!I!?#I!7!I"+"=%+"=#
2120 1?"+!?*+!=#~"=!+#?"="+!
2121 0?"+!?"I"?&+!="~!=!~"=!+%="+"
2122 /I!+!?)+!?!+!=$~!=!~!="+!="+"?!="?!
2123 .?%I"?%+%='?!=#~$="
2124 ,,!?%I"?(+$=$~!=#:"~$:!~!
2125 ,I!?!I!?"I"?!+#?"+!?!+#="~$:!~!:!~!:!,!:!,":#~!
2126 +I!?&+!="+!?#+$=!~":!~!:!~!:!,!:#,!:!,%:"
2127 *+!I!?!+$=!+!=!+!?$+#=!~":!~":#,$:",#:!,!:!
2128 *I!?"+!?!+!=$+!?#+#=#~":$,!:",!:!,&:"
2129 )I!?$=!~!=#+"?!+!=!+!=!~!="~!:!~":!,'.!,%:!~!
2130 (=!?"+!?!=!~$?"+!?!+!=#~"=",!="~$,$.",#.!:!=!
2131 (I"+"="~"=!+&=!~"=!~!,!~!+!=!?!+!?!=!I!?!+"=!.",!.!,":!
2132 %I$?!+!?!=%+!~!+#~!=!~#:#=!~!+!~!=#:!,%.!,!.!:"
2133 $I!?!=!?!I!+!?"+!=!~!=!~!?!I!?!=!+!=!~#:",!~"=!~!:"~!=!:",&:" '-/
2134 $?!+!I!?"+"=!+"~!,!:"+#~#:#,"=!~"=!,!~!,!.",!:".!:! */! !I!t!'!s! !a! !g!r!e!p!!! !/!
2135 $+"=!+!?!+"~!=!:!~!:"I!+!,!~!=!:!~!,!:!,$:!~".&:"~!,# (-/
2136 %~!=!~!=!:!.!+"~!:!,!.!,!~!=!:$.!,":!,!.!:!~!,!:!=!.#="~!,!:" ./!
2137 %=!~!?!+"?"+!=!~",!.!:!?!~!.!:!,!:!,#.!,!:","~!:!=!~!=!:",!~! ./!
2138 %+"~":!~!=#~!:!~!,!.!~!:",!~!=!~!.!:!,!.",!:!,":!=":!.!,!:!7! -/!
2139 %~",!:".#:!=!:!,!:"+!:!~!:!.!,!~!,!.#,!.!,$:"~!,":"~!=! */!
2140 &=!~!=#+!=!~",!.!:",#:#,!.",+:!,!.",!=!+!?!
2141 &~!=!~!=!~!:"~#:",!.!,#~!:!.!+!,!.",$.",$.#,!+!I!?!
2142 &~!="~!:!~":!~",!~!=!~":!,!:!~!,!:!,&.$,#."+!?!I!?!I!
2143 &~!=!~!=!+!,!:!~!:!=!,!:!~&:$,!.!,".!,".!,#."~!+!?$I!
2144 &~!=!~!="~!=!:!~":!,!~%:#,!:",!.!,#.",#I!7"I!?!+!?"I"
2145 &+!I!7!:#~"=!~!:!,!:"~$.!=!.!,!~!,$.#,!~!7!I#?!+!?"I"7!
2146 %7#?!+!~!:!=!~!=!~":!,!:"~":#.!,)7#I"?"I!7&
2147 %7#I!=":!=!~!:"~$:"~!:#,!:!,!:!~!:#,!7#I!?#7)
2148 $7$+!,!~!=#~!:!~!:!~$:#,!.!~!:!=!,":!7#I"?#7+=!?!
2149 $7#I!~!,!~#=!~!:"~!:!,!:!,#:!=!~",":!7$I!?#I!7*+!=!+"
2150 "I!7$I!,":!,!.!=":$,!:!,$:$7$I!+!?"I!7+?"I!7!I!7!,!
2151 !,!7%I!:",!."~":!,&.!,!:!~!I!7$I!+!?"I!7,?!I!7',!
2152 !7(,!.#~":!,%.!,!7%I!7!?#I"7,+!?!7*
2153 7+:!,!~#,"=!7'I!?#I"7/+!7+
2154 77I!+!7!?!7!I"71+!7,
2155 _BAR
2156
2157 $x =~ s/(.)(.)/$1x(ord($2)-32)/eg;
2158 App::Ack::print( $x );
2159 exit 0;
2160 }
2161
2162
2163 sub show_help {
2164 my $help_arg = shift || 0;
2165
2166 return show_help_types() if $help_arg =~ /^types?/;
2167
2168 App::Ack::print( <<"END_OF_HELP" );
2169 Usage: ack [OPTION]... PATTERN [FILES OR DIRECTORIES]
2170
2171 Search for PATTERN in each source file in the tree from the current
2172 directory on down. If any files or directories are specified, then
2173 only those files and directories are checked. ack may also search
2174 STDIN, but only if no file or directory arguments are specified,
2175 or if one of them is "-".
2176
2177 Default switches may be specified in ACK_OPTIONS environment variable or
2178 an .ackrc file. If you want no dependency on the environment, turn it
2179 off with --noenv.
2180
2181 Example: ack -i select
2182
2183 Searching:
2184 -i, --ignore-case Ignore case distinctions in PATTERN
2185 --[no]smart-case Ignore case distinctions in PATTERN,
2186 only if PATTERN contains no upper case.
2187 Ignored if -i is specified
2188 -v, --invert-match Invert match: select non-matching lines
2189 -w, --word-regexp Force PATTERN to match only whole words
2190 -Q, --literal Quote all metacharacters; PATTERN is literal
2191
2192 Search output:
2193 --lines=NUM Only print line(s) NUM of each file
2194 -l, --files-with-matches Only print filenames containing matches
2195 -L, --files-without-matches Only print filenames with no matches
2196 --output=expr Output the evaluation of expr for each line
2197 (turns off text highlighting)
2198 -o Show only the part of a line matching PATTERN
2199 Same as --output='\$&'
2200 --passthru Print all lines, whether matching or not
2201 --match PATTERN Specify PATTERN explicitly.
2202 -m, --max-count=NUM Stop searching in each file after NUM matches
2203 -1 Stop searching after one match of any kind
2204 -H, --with-filename Print the filename for each match (default:
2205 on unless explicitly searching a single file)
2206 -h, --no-filename Suppress the prefixing filename on output
2207 -c, --count Show number of lines matching per file
2208 --[no]column Show the column number of the first match
2209
2210 -A NUM, --after-context=NUM Print NUM lines of trailing context after matching
2211 lines.
2212 -B NUM, --before-context=NUM Print NUM lines of leading context before matching
2213 lines.
2214 -C [NUM], --context[=NUM] Print NUM lines (default 2) of output context.
2215
2216 --print0 Print null byte as separator between filenames,
2217 only works with -f, -g, -l, -L or -c.
2218
2219 -s Suppress error messages about nonexistent or
2220 unreadable files.
2221
2222
2223 File presentation:
2224 --pager=COMMAND Pipes all ack output through COMMAND. For example,
2225 --pager="less -R". Ignored if output is redirected.
2226 --nopager Do not send output through a pager. Cancels any
2227 setting in ~/.ackrc, ACK_PAGER or ACK_PAGER_COLOR.
2228 --[no]heading Print a filename heading above each file's results.
2229 (default: on when used interactively)
2230 --[no]break Print a break between results from different files.
2231 (default: on when used interactively)
2232 --group Same as --heading --break
2233 --nogroup Same as --noheading --nobreak
2234 --[no]color Highlight the matching text (default: on unless
2235 output is redirected, or on Windows)
2236 --[no]colour Same as --[no]color
2237 --color-filename=COLOR
2238 --color-match=COLOR
2239 --color-lineno=COLOR Set the color for filenames, matches, and line numbers.
2240 --flush Flush output immediately, even when ack is used
2241 non-interactively (when output goes to a pipe or
2242 file).
2243
2244
2245 File finding:
2246 -f Only print the files selected, without searching.
2247 The PATTERN must not be specified.
2248 -g Same as -f, but only select files matching PATTERN.
2249 --sort-files Sort the found files lexically.
2250 --show-types Show which types each file has.
2251 --files-from=FILE Read the list of files to search from FILE.
2252 -x Read the list of files to search from STDIN.
2253
2254 File inclusion/exclusion:
2255 --[no]ignore-dir=name Add/Remove directory from the list of ignored dirs
2256 --[no]ignore-directory=name Synonym for ignore-dir
2257 --ignore-file=filter Add filter for ignoring files
2258 -r, -R, --recurse Recurse into subdirectories (ack's default behavior)
2259 -n, --no-recurse No descending into subdirectories
2260 --[no]follow Follow symlinks. Default is off.
2261 -k, --known-types Include only files with types that ack recognizes.
2262
2263 --type=X Include only X files, where X is a recognized filetype.
2264 --type=noX Exclude X files.
2265 See "ack --help-types" for supported filetypes.
2266
2267 File type specification:
2268 --type-set TYPE:FILTER:FILTERARGS
2269 Files with the given FILTERARGS applied to the given
2270 FILTER are recognized as being of type TYPE. This
2271 replaces an existing definition for type TYPE.
2272 --type-add TYPE:FILTER:FILTERARGS
2273 Files with the given FILTERARGS applied to the given
2274 FILTER are recognized as being of type TYPE.
2275 --type-del TYPE Removes all filters associated with TYPE.
2276
2277
2278 Miscellaneous:
2279 --[no]env Ignore environment variables and global ackrc files. --env is legal but redundant.
2280 --ackrc=filename Specify an ackrc file to use
2281 --ignore-ack-defaults Ignore the default definitions that ack includes.
2282 --create-ackrc Outputs a default ackrc for your customization to standard output.
2283 --help, -? This help
2284 --help-types Display all known types
2285 --dump Dump information on which options are loaded from which RC files
2286 --[no]filter Force ack to treat standard input as a pipe (--filter) or tty (--nofilter)
2287 --man Man page
2288 --version Display version & copyright
2289 --thpppt Bill the Cat
2290 --bar The warning admiral
2291
2292 Exit status is 0 if match, 1 if no match.
2293
2294 This is version $VERSION of ack.
2295 END_OF_HELP
2296
2297 return;
2298 }
2299
2300
2301
2302 sub show_help_types {
2303 App::Ack::print( <<'END_OF_HELP' );
2304 Usage: ack [OPTION]... PATTERN [FILES OR DIRECTORIES]
2305
2306 The following is the list of filetypes supported by ack. You can
2307 specify a file type with the --type=TYPE format, or the --TYPE
2308 format. For example, both --type=perl and --perl work.
2309
2310 Note that some extensions may appear in multiple types. For example,
2311 .pod files are both Perl and Parrot.
2312
2313 END_OF_HELP
2314
2315 my @types = filetypes_supported();
2316 my $maxlen = 0;
2317 for ( @types ) {
2318 $maxlen = length if $maxlen < length;
2319 }
2320 for my $type ( sort @types ) {
2321 next if $type =~ /^-/; # Stuff to not show
2322 my $ext_list = $mappings{$type};
2323
2324 if ( ref $ext_list ) {
2325 $ext_list = join( '; ', map { $_->to_string } @{$ext_list} );
2326 }
2327 App::Ack::print( sprintf( " --[no]%-*.*s %s\n", $maxlen, $maxlen, $type, $ext_list ) );
2328 }
2329
2330 return;
2331 }
2332
2333 sub show_man {
2334 require Pod::Usage;
2335
2336 Pod::Usage::pod2usage({
2337 -input => $App::Ack::orig_program_name,
2338 -verbose => 2,
2339 -exitval => 0,
2340 });
2341
2342 return;
2343 }
2344
2345
2346 sub get_version_statement {
2347 require Config;
2348
2349 my $copyright = get_copyright();
2350 my $this_perl = $Config::Config{perlpath};
2351 if ($^O ne 'VMS') {
2352 my $ext = $Config::Config{_exe};
2353 $this_perl .= $ext unless $this_perl =~ m/$ext$/i;
2354 }
2355 my $ver = sprintf( '%vd', $^V );
2356
2357 my $git_revision = $GIT_REVISION ? " (git commit $GIT_REVISION)" : '';
2358
2359 return <<"END_OF_VERSION";
2360 ack ${VERSION}${git_revision}
2361 Running under Perl $ver at $this_perl
2362
2363 $copyright
2364
2365 This program is free software. You may modify or distribute it
2366 under the terms of the Artistic License v2.0.
2367 END_OF_VERSION
2368 }
2369
2370
2371 sub print_version_statement {
2372 App::Ack::print( get_version_statement() );
2373
2374 return;
2375 }
2376
2377
2378 sub get_copyright {
2379 return $COPYRIGHT;
2380 }
2381
2382
2383 sub load_colors {
2384 eval 'use Term::ANSIColor 1.10 ()';
2385
2386 $ENV{ACK_COLOR_MATCH} ||= 'black on_yellow';
2387 $ENV{ACK_COLOR_FILENAME} ||= 'bold green';
2388 $ENV{ACK_COLOR_LINENO} ||= 'bold yellow';
2389
2390 return;
2391 }
2392
2393
2394 # print subs added in order to make it easy for a third party
2395 # module (such as App::Wack) to redefine the display methods
2396 # and show the results in a different way.
2397 sub print { print {$fh} @_; return; }
2398 sub print_first_filename { App::Ack::print( $_[0], "\n" ); return; }
2399 sub print_blank_line { App::Ack::print( "\n" ); return; }
2400 sub print_separator { App::Ack::print( "--\n" ); return; }
2401 sub print_filename { App::Ack::print( $_[0], $_[1] ); return; }
2402 sub print_line_no { App::Ack::print( $_[0], $_[1] ); return; }
2403 sub print_column_no { App::Ack::print( $_[0], $_[1] ); return; }
2404 sub print_count {
2405 my $filename = shift;
2406 my $nmatches = shift;
2407 my $ors = shift;
2408 my $count = shift;
2409 my $show_filename = shift;
2410
2411 if ($show_filename) {
2412 App::Ack::print( $filename );
2413 App::Ack::print( ':', $nmatches ) if $count;
2414 }
2415 else {
2416 App::Ack::print( $nmatches ) if $count;
2417 }
2418 App::Ack::print( $ors );
2419
2420 return;
2421 }
2422
2423 sub print_count0 {
2424 my $filename = shift;
2425 my $ors = shift;
2426 my $show_filename = shift;
2427
2428 if ($show_filename) {
2429 App::Ack::print( $filename, ':0', $ors );
2430 }
2431 else {
2432 App::Ack::print( '0', $ors );
2433 }
2434
2435 return;
2436 }
2437
2438 sub set_up_pager {
2439 my $command = shift;
2440
2441 return if App::Ack::output_to_pipe();
2442
2443 my $pager;
2444 if ( not open( $pager, '|-', $command ) ) {
2445 App::Ack::die( qq{Unable to pipe to pager "$command": $!} );
2446 }
2447 $fh = $pager;
2448
2449 return;
2450 }
2451
2452
2453 sub output_to_pipe {
2454 return $output_to_pipe;
2455 }
2456
2457
2458 sub exit_from_ack {
2459 my $nmatches = shift;
2460
2461 my $rc = $nmatches ? 0 : 1;
2462 exit $rc;
2463 }
2464
2465 {
2466
2467 my @capture_indices;
2468 my $match_column_number;
2469
2470 sub does_match {
2471 my ( $opt, $line ) = @_;
2472
2473 my $re = $opt->{regex};
2474 my $invert = $opt->{v};
2475
2476 return unless $re;
2477
2478 $match_column_number = undef;
2479 @capture_indices = ();
2480
2481 if ( $invert ? $line !~ /$re/ : $line =~ /$re/ ) {
2482 if ( not $invert ) {
2483 # @- = @LAST_MATCH_START
2484 # @+ = @LAST_MATCH_END
2485 $match_column_number = $-[0] + 1;
2486
2487 if ( @- > 1 ) {
2488 @capture_indices = map {
2489 [ $-[$_], $+[$_] ]
2490 } ( 1 .. $#- );
2491 }
2492 }
2493 return 1;
2494 }
2495 else {
2496 return;
2497 }
2498 }
2499
2500 sub get_capture_indices {
2501 return @capture_indices;
2502 }
2503
2504 sub get_match_column {
2505 return $match_column_number;
2506 }
2507
2508 }
2509
2510 sub print_matches_in_resource {
2511 my ( $resource, $opt ) = @_;
2512
2513 my $passthru = $opt->{passthru};
2514 my $max_count = $opt->{m} || -1;
2515 my $nmatches = 0;
2516 my $filename = $resource->name;
2517 my $break = $opt->{break};
2518 my $heading = $opt->{heading};
2519 my $ors = $opt->{print0} ? "\0" : "\n";
2520 my $color = $opt->{color};
2521 my $print_filename = $opt->{show_filename};
2522
2523 my $has_printed_for_this_resource = 0;
2524
2525 App::Ack::iterate($resource, $opt, sub {
2526 if ( App::Ack::does_match($opt, $_) ) {
2527 if( !$has_printed_for_this_resource ) {
2528 if( $break && has_printed_something() ) {
2529 App::Ack::print_blank_line();
2530 }
2531 if( $print_filename) {
2532 if( $heading ) {
2533 my $filename = $resource->name;
2534 if($color) {
2535 $filename = Term::ANSIColor::colored($filename,
2536 $ENV{ACK_COLOR_FILENAME});
2537 }
2538 App::Ack::print_filename( $filename, $ors );
2539 }
2540 }
2541 }
2542 App::Ack::print_line_with_context($opt, $filename, $_, $.);
2543 $has_printed_for_this_resource = 1;
2544 $nmatches++;
2545 $max_count--;
2546 }
2547 elsif ( $passthru ) {
2548 chomp;
2549 if( $break && !$has_printed_for_this_resource && has_printed_something() ) {
2550 App::Ack::print_blank_line();
2551 }
2552 App::Ack::print_line_with_options($opt, $filename, $_, $., ':');
2553 $has_printed_for_this_resource = 1;
2554 }
2555 return $max_count != 0;
2556 });
2557
2558 return $nmatches;
2559 }
2560
2561 sub count_matches_in_resource {
2562 my ( $resource, $opt ) = @_;
2563
2564 my $nmatches = 0;
2565
2566 App::Ack::iterate( $resource, $opt, sub {
2567 ++$nmatches if App::Ack::does_match($opt, $_);
2568 return 1;
2569 } );
2570
2571 return $nmatches;
2572 }
2573
2574 sub resource_has_match {
2575 my ( $resource, $opt ) = @_;
2576
2577 return count_matches_in_resource($resource, $opt) > 0;
2578 }
2579
2580 {
2581
2582 my @before_ctx_lines;
2583 my @after_ctx_lines;
2584 my $is_iterating;
2585
2586 sub get_context {
2587 if ( not $is_iterating ) {
2588 Carp::croak( 'get_context() called outside of iterate()' );
2589 }
2590
2591 return (
2592 scalar(@before_ctx_lines) ? \@before_ctx_lines : undef,
2593 scalar(@after_ctx_lines) ? \@after_ctx_lines : undef,
2594 );
2595 }
2596
2597 sub iterate {
2598 my ( $resource, $opt, $cb ) = @_;
2599
2600 $is_iterating = 1;
2601
2602 local $opt->{before_context} = $opt->{output} ? 0 : $opt->{before_context};
2603 local $opt->{after_context} = $opt->{output} ? 0 : $opt->{after_context};
2604
2605 my $n_before_ctx_lines = $opt->{before_context} || 0;
2606 my $n_after_ctx_lines = $opt->{after_context} || 0;
2607 my $current_line;
2608
2609 @after_ctx_lines = @before_ctx_lines = ();
2610
2611 if ( $resource->next_text() ) {
2612 $current_line = $_; # prime the first line of input
2613 }
2614
2615 while ( defined $current_line ) {
2616 while ( (@after_ctx_lines < $n_after_ctx_lines) && $resource->next_text() ) {
2617 push @after_ctx_lines, $_;
2618 }
2619
2620 local $_ = $current_line;
2621 my $former_dot_period = $.;
2622 $. = $. - @after_ctx_lines;
2623
2624 last unless $cb->();
2625
2626 # I tried doing this with local(), but for some reason,
2627 # $. continued to have its new value after the exit of the
2628 # enclosing block. I'm guessing that $. has some extra
2629 # magic associated with it or something. If someone can
2630 # tell me why this happened, I would love to know!
2631 $. = $former_dot_period; # XXX this won't happen on an exception
2632
2633 push @before_ctx_lines, $current_line;
2634 if($n_after_ctx_lines) {
2635 $current_line = shift @after_ctx_lines;
2636 }
2637 elsif($resource->next_text()) {
2638 $current_line = $_;
2639 }
2640 else {
2641 undef $current_line;
2642 }
2643 shift @before_ctx_lines while @before_ctx_lines > $n_before_ctx_lines;
2644 }
2645
2646 $is_iterating = 0; # XXX this won't happen on an exception
2647 # then again, do we care? ack doesn't really
2648 # handle exceptions anyway.
2649
2650 return;
2651 }
2652
2653 }
2654
2655 my $has_printed_something;
2656
2657 BEGIN {
2658 $has_printed_something = 0;
2659 }
2660
2661 sub has_printed_something {
2662 return $has_printed_something;
2663 }
2664
2665 sub print_line_with_options {
2666 my ( $opt, $filename, $line, $line_no, $separator ) = @_;
2667
2668 $has_printed_something = 1;
2669
2670 my $print_filename = $opt->{show_filename};
2671 my $print_column = $opt->{column};
2672 my $ors = $opt->{print0} ? "\0" : "\n";
2673 my $heading = $opt->{heading};
2674 my $output_expr = $opt->{output};
2675 my $re = $opt->{regex};
2676 my $color = $opt->{color};
2677
2678 my @line_parts;
2679
2680 if( $color ) {
2681 $filename = Term::ANSIColor::colored($filename,
2682 $ENV{ACK_COLOR_FILENAME});
2683 $line_no = Term::ANSIColor::colored($line_no,
2684 $ENV{ACK_COLOR_LINENO});
2685 }
2686
2687 if($print_filename) {
2688 if( $heading ) {
2689 push @line_parts, $line_no;
2690 }
2691 else {
2692 push @line_parts, $filename, $line_no;
2693 }
2694
2695 if( $print_column ) {
2696 push @line_parts, get_match_column();
2697 }
2698 }
2699 if( $output_expr ) {
2700 # XXX avoid re-evaluation if we can
2701 while( $line =~ /$re/g ) {
2702 my $output = eval $output_expr;
2703 App::Ack::print( join( $separator, @line_parts, $output ), $ors );
2704 }
2705 }
2706 else {
2707 my @capture_indices = get_capture_indices();
2708 if( @capture_indices ) {
2709 my $offset = 0; # additional offset for when we add stuff
2710
2711 foreach my $index_pair ( @capture_indices ) {
2712 my ( $match_start, $match_end ) = @{$index_pair};
2713
2714 my $substring = substr( $line,
2715 $offset + $match_start, $match_end - $match_start );
2716 my $substitution = Term::ANSIColor::colored( $substring,
2717 $ENV{ACK_COLOR_MATCH} );
2718
2719 substr( $line, $offset + $match_start,
2720 $match_end - $match_start, $substitution );
2721
2722 $offset += length( $substitution ) - length( $substring );
2723 }
2724 }
2725 elsif( $color ) {
2726 # XXX I know $& is a no-no; fix it later
2727 if($line =~ s/$re/Term::ANSIColor::colored($&, $ENV{ACK_COLOR_MATCH})/ge) {
2728 $line .= "\033[0m\033[K";
2729 }
2730 }
2731
2732 push @line_parts, $line;
2733 App::Ack::print( join( $separator, @line_parts ), $ors );
2734 }
2735
2736 return;
2737 }
2738
2739 {
2740
2741 my $is_first_match;
2742 my $previous_file_processed;
2743 my $previous_line_printed;
2744
2745 BEGIN {
2746 $is_first_match = 1;
2747 $previous_line_printed = -1;
2748 }
2749
2750 sub print_line_with_context {
2751 my ( $opt, $filename, $matching_line, $line_no ) = @_;
2752
2753 my $heading = $opt->{heading};
2754
2755 if( !defined($previous_file_processed) ||
2756 $previous_file_processed ne $filename ) {
2757 $previous_file_processed = $filename;
2758 $previous_line_printed = -1;
2759
2760 if( $heading ) {
2761 $is_first_match = 1;
2762 }
2763 }
2764
2765 my $ors = $opt->{print0} ? "\0" : "\n";
2766 my $match_word = $opt->{w};
2767 my $re = $opt->{regex};
2768 my $is_tracking_context = $opt->{after_context} || $opt->{before_context};
2769 my $output_expr = $opt->{output};
2770
2771 chomp $matching_line;
2772
2773 my ( $before_context, $after_context ) = get_context();
2774
2775 if ( $before_context ) {
2776 my $first_line = $. - @{$before_context};
2777
2778 if ( $first_line <= $previous_line_printed ) {
2779 splice @{$before_context}, 0, $previous_line_printed - $first_line + 1;
2780 $first_line = $. - @{$before_context};
2781 }
2782 if ( @{$before_context} ) {
2783 my $offset = @{$before_context};
2784
2785 if( !$is_first_match && $previous_line_printed != $first_line - 1 ) {
2786 App::Ack::print('--', $ors);
2787 }
2788 foreach my $line (@{$before_context}) {
2789 my $context_line_no = $. - $offset;
2790 if ( $context_line_no <= $previous_line_printed ) {
2791 next;
2792 }
2793
2794 chomp $line;
2795 App::Ack::print_line_with_options($opt, $filename, $line, $context_line_no, '-');
2796 $previous_line_printed = $context_line_no;
2797 $offset--;
2798 }
2799 }
2800 }
2801
2802 if ( $. > $previous_line_printed ) {
2803 if( $is_tracking_context && !$is_first_match && $previous_line_printed != $. - 1 ) {
2804 App::Ack::print('--', $ors);
2805 }
2806
2807 App::Ack::print_line_with_options($opt, $filename, $matching_line, $line_no, ':');
2808 $previous_line_printed = $.;
2809 }
2810
2811 if($after_context) {
2812 my $offset = 1;
2813 foreach my $line (@{$after_context}) {
2814 # XXX improve this!
2815 if ( $previous_line_printed >= $. + $offset ) {
2816 $offset++;
2817 next;
2818 }
2819 chomp $line;
2820 my $separator = App::Ack::does_match( $opt, $line ) ? ':' : '-';
2821 App::Ack::print_line_with_options($opt, $filename, $line, $. + $offset, $separator);
2822 $previous_line_printed = $. + $offset;
2823 $offset++;
2824 }
2825 }
2826
2827 $is_first_match = 0;
2828
2829 return;
2830 }
2831
2832 }
2833
2834 # inefficient, but functional
2835 sub filetypes {
2836 my ( $resource ) = @_;
2837
2838 my @matches;
2839
2840 foreach my $k (keys %mappings) {
2841 my $filters = $mappings{$k};
2842
2843 foreach my $filter (@{$filters}) {
2844 # clone the resource
2845 my $clone = $resource->clone;
2846 if ( $filter->filter($clone) ) {
2847 push @matches, $k;
2848 last;
2849 }
2850 }
2851 }
2852
2853 return sort @matches;
2854 }
2855
2856 # returns a (fairly) unique identifier for a file
2857 # use this function to compare two files to see if they're
2858 # equal (ie. the same file, but with a different path/links/etc)
2859 sub get_file_id {
2860 my ( $filename ) = @_;
2861
2862 if ( $is_windows ) {
2863 return File::Next::reslash( $filename );
2864 }
2865 else {
2866 # XXX is this the best method? it always hits the FS
2867 if( my ( $dev, $inode ) = (stat($filename))[0, 1] ) {
2868 return join(':', $dev, $inode);
2869 }
2870 else {
2871 # XXX this could be better
2872 return $filename;
2873 }
2874 }
2875 }
2876
2877 sub create_ackrc {
2878 print "$_\n" for ( '--ignore-ack-defaults', App::Ack::ConfigDefault::options() );
2879 }
2880
2881
2882
2883 1; # End of App::Ack
2884 package App::Ack::Resource;
2885
2886
2887 use warnings;
2888 use strict;
2889 use overload
2890 '""' => 'name';
2891
2892 sub FAIL {
2893 require Carp;
2894 Carp::confess( 'Must be overloaded' );
2895 }
2896
2897
2898 sub new {
2899 return FAIL();
2900 }
2901
2902
2903 sub name {
2904 return FAIL();
2905 }
2906
2907
2908 sub is_binary {
2909 return FAIL();
2910 }
2911
2912
2913
2914 sub needs_line_scan {
2915 return FAIL();
2916 }
2917
2918
2919 sub reset {
2920 return FAIL();
2921 }
2922
2923
2924 sub next_text {
2925 return FAIL();
2926 }
2927
2928
2929 sub close {
2930 return FAIL();
2931 }
2932
2933
2934 sub clone {
2935 return FAIL();
2936 }
2937
2938 1;
2939 package App::Ack::Resources;
2940
2941
2942
2943 use warnings;
2944 use strict;
2945
2946
2947 sub from_argv {
2948 my $class = shift;
2949 my $opt = shift;
2950 my $start = shift;
2951
2952 my $self = bless {}, $class;
2953
2954 my $file_filter = undef;
2955 my $descend_filter = $opt->{descend_filter};
2956
2957 if( $opt->{n} ) {
2958 $descend_filter = sub {
2959 return 0;
2960 };
2961 }
2962
2963 $self->{iter} =
2964 File::Next::files( {
2965 file_filter => $opt->{file_filter},
2966 descend_filter => $descend_filter,
2967 error_handler => sub { my $msg = shift; App::Ack::warn( $msg ) },
2968 sort_files => $opt->{sort_files},
2969 follow_symlinks => $opt->{follow},
2970 }, @{$start} );
2971
2972 return $self;
2973 }
2974
2975
2976 sub from_file {
2977 my $class = shift;
2978 my $opt = shift;
2979 my $file = shift;
2980
2981 my $iter =
2982 File::Next::from_file( {
2983 error_handler => sub { my $msg = shift; App::Ack::warn( $msg ) },
2984 warning_handler => sub { my $msg = shift; App::Ack::warn( $msg ) },
2985 sort_files => $opt->{sort_files},
2986 }, $file ) or return undef;
2987
2988 return bless {
2989 iter => $iter,
2990 }, $class;
2991 }
2992
2993 # This is for reading input lines from STDIN, not the list of files from STDIN
2994 sub from_stdin {
2995 my $class = shift;
2996 my $opt = shift;
2997
2998 my $self = bless {}, $class;
2999
3000 my $has_been_called = 0;
3001
3002 $self->{iter} = sub {
3003 if ( !$has_been_called ) {
3004 $has_been_called = 1;
3005 return '-';
3006 }
3007 return;
3008 };
3009
3010 return $self;
3011 }
3012
3013 sub next {
3014 my $self = shift;
3015
3016 my $file = $self->{iter}->() or return;
3017
3018 return App::Ack::Resource::Basic->new( $file );
3019 }
3020
3021 1;
3022 package App::Ack::Resource::Basic;
3023
3024
3025 use warnings;
3026 use strict;
3027
3028 BEGIN {
3029 our @ISA = 'App::Ack::Resource';
3030 }
3031
3032
3033 sub new {
3034 my $class = shift;
3035 my $filename = shift;
3036
3037 my $self = bless {
3038 filename => $filename,
3039 fh => undef,
3040 opened => undef,
3041 }, $class;
3042
3043 if ( $self->{filename} eq '-' ) {
3044 $self->{fh} = *STDIN;
3045 }
3046 else {
3047 if ( !open( $self->{fh}, '<', $self->{filename} ) && $App::Ack::report_bad_filenames ) {
3048 App::Ack::warn( "$self->{filename}: $!" );
3049 return;
3050 }
3051 }
3052
3053 return $self;
3054 }
3055
3056
3057 sub name {
3058 my $self = shift;
3059
3060 return $self->{filename};
3061 }
3062
3063
3064
3065 sub needs_line_scan {
3066 my $self = shift;
3067 my $opt = shift;
3068
3069 return 1 if $opt->{v};
3070
3071 my $size = -s $self->{fh};
3072 if ( $size == 0 ) {
3073 return 0;
3074 }
3075 elsif ( $size > 100_000 ) {
3076 return 1;
3077 }
3078
3079 my $buffer;
3080 my $rc = sysread( $self->{fh}, $buffer, $size );
3081 if ( !defined($rc) && $App::Ack::report_bad_filenames ) {
3082 App::Ack::warn( "$self->{filename}: $!" );
3083 return 1;
3084 }
3085 return 0 unless $rc && ( $rc == $size );
3086
3087 my $regex = $opt->{regex};
3088 return $buffer =~ /$regex/m;
3089 }
3090
3091
3092 sub reset {
3093 my $self = shift;
3094
3095 if( !seek( $self->{fh}, 0, 0 ) && $App::Ack::report_bad_filenames ) {
3096 App::Ack::warn( "$self->{filename}: $!" );
3097 }
3098
3099 return;
3100 }
3101
3102
3103 sub next_text {
3104 if ( defined ($_ = readline $_[0]->{fh}) ) {
3105 $. = ++$_[0]->{line};
3106 s/[\r\n]+$//; # chomp may not handle this
3107 $_ .= "\n"; # add back newline (XXX make it native)
3108 return 1;
3109 }
3110
3111 return;
3112 }
3113
3114
3115 sub close {
3116 my $self = shift;
3117
3118 if ( !close($self->{fh}) && $App::Ack::report_bad_filenames ) {
3119 App::Ack::warn( $self->name() . ": $!" );
3120 }
3121
3122 return;
3123 }
3124
3125
3126 sub clone {
3127 my ( $self ) = @_;
3128
3129 return __PACKAGE__->new($self->name);
3130 }
3131
3132
3133 1;
3134 package App::Ack::Filter;
3135
3136 use strict;
3137 use warnings;
3138 use overload
3139 '""' => 'to_string';
3140
3141 use Carp 1.04 ();
3142
3143 my %filter_types;
3144
3145
3146 sub create_filter {
3147 my ( undef, $type, @args ) = @_;
3148
3149 if ( my $package = $filter_types{$type} ) {
3150 return $package->new(@args);
3151 }
3152 Carp::croak "Unknown filter type '$type'";
3153 }
3154
3155
3156 sub register_filter {
3157 my ( undef, $type, $package ) = @_;
3158
3159 $filter_types{$type} = $package;
3160
3161 return;
3162 }
3163
3164
3165 sub invert {
3166 my ( $self ) = @_;
3167
3168 return App::Ack::Filter::Inverse->new( $self );
3169 }
3170
3171
3172 sub is_inverted {
3173 return 0;
3174 }
3175
3176
3177 sub to_string {
3178 my ( $self ) = @_;
3179
3180 return '(unimplemented to_string)';
3181 }
3182
3183
3184 sub inspect {
3185 my ( $self ) = @_;
3186
3187 return ref($self);
3188 }
3189
3190 1;
3191 package App::Ack::Filter::Extension;
3192
3193 use strict;
3194 use warnings;
3195 BEGIN {
3196 our @ISA = 'App::Ack::Filter';
3197 }
3198
3199 sub new {
3200 my ( $class, @extensions ) = @_;
3201
3202 my $exts = join('|', map { "\Q$_\E"} @extensions);
3203 my $re = qr/[.](?:$exts)$/i;
3204
3205 return bless {
3206 extensions => \@extensions,
3207 regex => $re,
3208 }, $class;
3209 }
3210
3211 sub filter {
3212 my ( $self, $resource ) = @_;
3213
3214 my $re = $self->{'regex'};
3215
3216 return $resource->name =~ /$re/;
3217 }
3218
3219 sub inspect {
3220 my ( $self ) = @_;
3221
3222 my $re = $self->{'regex'};
3223
3224 return ref($self) . " - $re";
3225 }
3226
3227 sub to_string {
3228 my ( $self ) = @_;
3229
3230 my $exts = $self->{'extensions'};
3231
3232 return join(' ', map { ".$_" } @{$exts});
3233 }
3234
3235 BEGIN {
3236 App::Ack::Filter->register_filter(ext => __PACKAGE__);
3237 }
3238
3239 1;
3240 package App::Ack::Filter::FirstLineMatch;
3241
3242 use strict;
3243 use warnings;
3244 BEGIN {
3245 our @ISA = 'App::Ack::Filter';
3246 }
3247
3248 sub new {
3249 my ( $class, $re ) = @_;
3250
3251 $re =~ s{^/|/$}{}g; # XXX validate?
3252 $re = qr{$re}i;
3253
3254 return bless {
3255 regex => $re,
3256 }, $class;
3257 }
3258
3259 # This test reads the first 250 characters of a file, then just uses the
3260 # first line found in that. This prevents reading something like an entire
3261 # .min.js file (which might be only one "line" long) into memory.
3262
3263 sub filter {
3264 my ( $self, $resource ) = @_;
3265
3266 my $re = $self->{'regex'};
3267
3268 my $buffer;
3269 my $rc = sysread( $resource->{fh}, $buffer, 250 );
3270 return unless $rc;
3271 $buffer =~ s/[\r\n].*//s;
3272
3273 return $buffer =~ /$re/;
3274 }
3275
3276 sub inspect {
3277 my ( $self ) = @_;
3278
3279 my $re = $self->{'regex'};
3280
3281 return ref($self) . " - $re";
3282 }
3283
3284 sub to_string {
3285 my ( $self ) = @_;
3286
3287 (my $re = $self->{regex}) =~ s{\([^:]*:(.*)\)$}{$1};
3288
3289 return "first line matches /$re/";
3290 }
3291
3292 BEGIN {
3293 App::Ack::Filter->register_filter(firstlinematch => __PACKAGE__);
3294 }
3295
3296 1;
3297 package App::Ack::Filter::Is;
3298
3299 use strict;
3300 use warnings;
3301 BEGIN {
3302 our @ISA = 'App::Ack::Filter';
3303 }
3304
3305 use File::Spec 3.00 ();
3306
3307 sub new {
3308 my ( $class, $filename ) = @_;
3309
3310 return bless {
3311 filename => $filename,
3312 }, $class;
3313 }
3314
3315 sub filter {
3316 my ( $self, $resource ) = @_;
3317
3318 my $filename = $self->{'filename'};
3319 my $base = (File::Spec->splitpath($resource->name))[2];
3320
3321 return $base eq $filename;
3322 }
3323
3324 sub inspect {
3325 my ( $self ) = @_;
3326
3327 my $filename = $self->{'filename'};
3328
3329 return ref($self) . " - $filename";
3330 }
3331
3332 sub to_string {
3333 my ( $self ) = @_;
3334
3335 my $filename = $self->{'filename'};
3336 }
3337
3338 BEGIN {
3339 App::Ack::Filter->register_filter(is => __PACKAGE__);
3340 }
3341
3342 1;
3343 package App::Ack::Filter::Match;
3344
3345 use strict;
3346 use warnings;
3347 BEGIN {
3348 our @ISA = 'App::Ack::Filter';
3349 }
3350
3351 use File::Spec 3.00;
3352
3353 sub new {
3354 my ( $class, $re ) = @_;
3355
3356 $re =~ s{^/|/$}{}g; # XXX validate?
3357 $re = qr/$re/i;
3358
3359 return bless {
3360 regex => $re,
3361 }, $class;
3362 }
3363
3364 sub filter {
3365 my ( $self, $resource ) = @_;
3366
3367 my $re = $self->{'regex'};
3368 my $base = (File::Spec->splitpath($resource->name))[2];
3369
3370 return $base =~ /$re/;
3371 }
3372
3373 sub inspect {
3374 my ( $self ) = @_;
3375
3376 my $re = $self->{'regex'};
3377
3378 print ref($self) . " - $re";
3379 }
3380
3381 sub to_string {
3382 my ( $self ) = @_;
3383
3384 my $re = $self->{'regex'};
3385
3386 return "filename matches $re";
3387 }
3388
3389 BEGIN {
3390 App::Ack::Filter->register_filter(match => __PACKAGE__);
3391 }
3392
3393 1;
3394 package App::Ack::Filter::Default;
3395
3396 use strict;
3397 use warnings;
3398 BEGIN {
3399 our @ISA = 'App::Ack::Filter';
3400 }
3401
3402 sub new {
3403 my ( $class ) = @_;
3404
3405 return bless {}, $class;
3406 }
3407
3408 sub filter {
3409 my ( $self, $resource ) = @_;
3410
3411 return -T $resource->name;
3412 }
3413
3414 1;
3415 package App::Ack::Filter::Inverse;
3416
3417 use strict;
3418 use warnings;
3419 BEGIN {
3420 our @ISA = 'App::Ack::Filter';
3421 }
3422
3423 sub new {
3424 my ( $class, $filter ) = @_;
3425
3426 return bless {
3427 filter => $filter,
3428 }, $class;
3429 }
3430
3431 sub filter {
3432 my ( $self, $resource ) = @_;
3433
3434 my $filter = $self->{'filter'};
3435 return !$filter->filter( $resource );
3436 }
3437
3438 sub invert {
3439 my $self = shift;
3440
3441 return $self->{'filter'};
3442 }
3443
3444 sub is_inverted {
3445 return 1;
3446 }
3447
3448 sub inspect {
3449 my ( $self ) = @_;
3450
3451 my $filter = $self->{'filter'};
3452
3453 return "!$filter";
3454 }
3455
3456 1;
3457 package App::Ack::ConfigFinder;
3458
3459
3460 use strict;
3461 use warnings;
3462
3463 use Cwd 3.00 ();
3464 use File::Spec 3.00;
3465
3466 BEGIN {
3467 if ($App::Ack::is_windows) {
3468 require Win32;
3469 }
3470 }
3471
3472
3473 sub new {
3474 my ( $class ) = @_;
3475
3476 return bless {}, $class;
3477 }
3478
3479 sub _remove_redundancies {
3480 my ( @configs ) = @_;
3481
3482 my %dev_and_inode_seen;
3483
3484 foreach my $path ( @configs ) {
3485 my ( $dev, $inode ) = (stat $path)[0, 1];
3486
3487 if( defined($dev) ) {
3488 if( $dev_and_inode_seen{"$dev:$inode"} ) {
3489 undef $path;
3490 }
3491 else {
3492 $dev_and_inode_seen{"$dev:$inode"} = 1;
3493 }
3494 }
3495 }
3496 return grep { defined() } @configs;
3497 }
3498
3499 sub _check_for_ackrc {
3500 return unless defined $_[0];
3501
3502 my @files = grep { -f }
3503 map { File::Spec->catfile(@_, $_) }
3504 qw(.ackrc _ackrc);
3505
3506 die File::Spec->catdir(@_) . " contains both .ackrc and _ackrc.\n" .
3507 "Please remove one of those files.\n"
3508 if @files > 1;
3509
3510 return wantarray ? @files : $files[0];
3511 } # end _check_for_ackrc
3512
3513
3514 sub find_config_files {
3515 my @config_files;
3516
3517 if($App::Ack::is_windows) {
3518 push @config_files, map { File::Spec->catfile($_, 'ackrc') } (
3519 Win32::GetFolderPath(Win32::CSIDL_COMMON_APPDATA()),
3520 Win32::GetFolderPath(Win32::CSIDL_APPDATA()),
3521 );
3522 }
3523 else {
3524 push @config_files, '/etc/ackrc';
3525 }
3526
3527 if ( $ENV{'ACKRC'} && -f $ENV{'ACKRC'} ) {
3528 push @config_files, $ENV{'ACKRC'};
3529 }
3530 else {
3531 push @config_files, _check_for_ackrc($ENV{'HOME'});
3532 }
3533
3534 my @dirs = File::Spec->splitdir(Cwd::getcwd());
3535 while(@dirs) {
3536 my $ackrc = _check_for_ackrc(@dirs);
3537 if(defined $ackrc) {
3538 push @config_files, $ackrc;
3539 last;
3540 }
3541 pop @dirs;
3542 }
3543
3544 # XXX we only test for existence here, so if the file is
3545 # deleted out from under us, this will fail later. =(
3546 return _remove_redundancies( @config_files );
3547 }
3548
3549 1;
3550 package App::Ack::ConfigLoader;
3551
3552 use strict;
3553 use warnings;
3554
3555 use Carp 1.04 ();
3556 use Getopt::Long 2.36 ();
3557 use Text::ParseWords 3.1 ();
3558
3559
3560 my @INVALID_COMBINATIONS;
3561
3562 BEGIN {
3563 my @context = qw( -A -B -C --after-context --before-context --context );
3564 my @pretty = qw( --heading --group --break );
3565 my @filename = qw( -h -H --with-filename --no-filename );
3566
3567 @INVALID_COMBINATIONS = (
3568 # XXX normalize
3569 [qw(-l)] => [@context, @pretty, @filename, qw(-L -o --passthru --output --max-count --column -f -g --show-types)],
3570 [qw(-L)] => [@context, @pretty, @filename, qw(-l -o --passthru --output --max-count --column -f -g --show-types -c --count)],
3571 [qw(--line)] => [@context, @pretty, @filename, qw(-l --files-with-matches --files-without-matches -L -o --passthru --match -m --max-count -1 -c --count --column --print0 -f -g --show-types)],
3572 [qw(-o)] => [@context, qw(--output -c --count --column --column -f --show-types)],
3573 [qw(--passthru)] => [@context, qw(--output --column -m --max-count -1 -c --count -f -g)],
3574 [qw(--output)] => [@context, qw(-c --count -f -g)],
3575 [qw(--match)] => [qw(-f -g)],
3576 [qw(-m --max-count)] => [qw(-1 -f -g -c --count)],
3577 [qw(-h --no-filename)] => [qw(-H --with-filename -f -g --group --heading)],
3578 [qw(-H --with-filename)] => [qw(-h --no-filename -f -g)],
3579 [qw(-c --count)] => [@context, @pretty, qw(--column -f -g)],
3580 [qw(--column)] => [qw(-f -g)],
3581 [@context] => [qw(-f -g)],
3582 [qw(-f)] => [qw(-g), @pretty],
3583 [qw(-g)] => [qw(-f), @pretty],
3584 );
3585 }
3586
3587 sub process_filter_spec {
3588 my ( $spec ) = @_;
3589
3590 if ( $spec =~ /^(\w+):(\w+):(.*)/ ) {
3591 my ( $type_name, $ext_type, $arguments ) = ( $1, $2, $3 );
3592
3593 return ( $type_name,
3594 App::Ack::Filter->create_filter($ext_type, split(/,/, $arguments)) );
3595 }
3596 elsif ( $spec =~ /^(\w+)=(.*)/ ) { # Check to see if we have ack1-style argument specification.
3597 my ( $type_name, $extensions ) = ( $1, $2 );
3598
3599 my @extensions = split(/,/, $extensions);
3600 foreach my $extension ( @extensions ) {
3601 $extension =~ s/^[.]//;
3602 }
3603
3604 return ( $type_name, App::Ack::Filter->create_filter('ext', @extensions) );
3605 }
3606 else {
3607 Carp::croak "invalid filter specification '$spec'";
3608 }
3609 }
3610
3611 sub process_filetypes {
3612 my ( $opt, $arg_sources ) = @_;
3613
3614 Getopt::Long::Configure('default', 'no_auto_help', 'no_auto_version'); # start with default options, minus some annoying ones
3615 Getopt::Long::Configure(
3616 'no_ignore_case',
3617 'no_auto_abbrev',
3618 'pass_through',
3619 );
3620 my %additional_specs;
3621
3622 my $add_spec = sub {
3623 my ( undef, $spec ) = @_;
3624
3625 my ( $name, $filter ) = process_filter_spec($spec);
3626
3627 push @{ $App::Ack::mappings{$name} }, $filter;
3628
3629 $additional_specs{$name . '!'} = sub {
3630 my ( undef, $value ) = @_;
3631
3632 my @filters = @{ $App::Ack::mappings{$name} };
3633 if ( not $value ) {
3634 @filters = map { $_->invert() } @filters;
3635 }
3636
3637 push @{ $opt->{'filters'} }, @filters;
3638 };
3639 };
3640
3641 my $set_spec = sub {
3642 my ( undef, $spec ) = @_;
3643
3644 my ( $name, $filter ) = process_filter_spec($spec);
3645
3646 $App::Ack::mappings{$name} = [ $filter ];
3647
3648 $additional_specs{$name . '!'} = sub {
3649 my ( undef, $value ) = @_;
3650
3651 my @filters = @{ $App::Ack::mappings{$name} };
3652 if ( not $value ) {
3653 @filters = map { $_->invert() } @filters;
3654 }
3655
3656 push @{ $opt->{'filters'} }, @filters;
3657 };
3658 };
3659
3660 my $delete_spec = sub {
3661 my ( undef, $name ) = @_;
3662
3663 delete $App::Ack::mappings{$name};
3664 delete $additional_specs{$name . '!'};
3665 };
3666
3667 my %type_arg_specs = (
3668 'type-add=s' => $add_spec,
3669 'type-set=s' => $set_spec,
3670 'type-del=s' => $delete_spec,
3671 );
3672
3673 for ( my $i = 0; $i < @{$arg_sources}; $i += 2) {
3674 my ( $source_name, $args ) = @{$arg_sources}[ $i, $i + 1];
3675
3676 if ( ref($args) ) {
3677 # $args are modified in place, so no need to munge $arg_sources
3678 Getopt::Long::GetOptionsFromArray($args, %type_arg_specs);
3679 }
3680 else {
3681 ( undef, $arg_sources->[$i + 1] ) =
3682 Getopt::Long::GetOptionsFromString($args, %type_arg_specs);
3683 }
3684 }
3685
3686 $additional_specs{'k|known-types'} = sub {
3687 my ( undef, $value ) = @_;
3688
3689 my @filters = map { @{$_} } values(%App::Ack::mappings);
3690
3691 push @{ $opt->{'filters'} }, @filters;
3692 };
3693
3694 return \%additional_specs;
3695 }
3696
3697 sub removed_option {
3698 my ( $option, $explanation ) = @_;
3699
3700 $explanation ||= '';
3701 return sub {
3702 warn "Option '$option' is not valid in ack 2\n$explanation";
3703 exit 1;
3704 };
3705 }
3706
3707 sub get_arg_spec {
3708 my ( $opt, $extra_specs ) = @_;
3709
3710 my $dash_a_explanation = <<EOT;
3711 This is because we now have -k/--known-types which makes it only select files
3712 of known types, rather than any text file (which is the behavior of ack 1.x).
3713 EOT
3714
3715 return {
3716 1 => sub { $opt->{1} = $opt->{m} = 1 },
3717 'A|after-context=i' => \$opt->{after_context},
3718 'B|before-context=i'
3719 => \$opt->{before_context},
3720 'C|context:i' => sub { shift; my $val = shift; $opt->{before_context} = $opt->{after_context} = ($val || 2) },
3721 'a' => removed_option('-a', $dash_a_explanation),
3722 'all' => removed_option('--all', $dash_a_explanation),
3723 'break!' => \$opt->{break},
3724 c => \$opt->{count},
3725 'color|colour!' => \$opt->{color},
3726 'color-match=s' => \$ENV{ACK_COLOR_MATCH},
3727 'color-filename=s' => \$ENV{ACK_COLOR_FILENAME},
3728 'color-lineno=s' => \$ENV{ACK_COLOR_LINENO},
3729 'column!' => \$opt->{column},
3730 count => \$opt->{count},
3731 'create-ackrc' => sub { App::Ack::create_ackrc(); exit; },
3732 'env!' => sub {
3733 my ( undef, $value ) = @_;
3734
3735 if ( !$value ) {
3736 $opt->{noenv_seen} = 1;
3737 }
3738 },
3739 f => \$opt->{f},
3740 'files-from=s' => \$opt->{files_from},
3741 'filter!' => \$App::Ack::is_filter_mode,
3742 flush => \$opt->{flush},
3743 'follow!' => \$opt->{follow},
3744 g => \$opt->{g},
3745 G => removed_option('-G'),
3746 'group!' => sub { shift; $opt->{heading} = $opt->{break} = shift },
3747 'heading!' => \$opt->{heading},
3748 'h|no-filename' => \$opt->{h},
3749 'H|with-filename' => \$opt->{H},
3750 'i|ignore-case' => \$opt->{i},
3751 'ignore-directory|ignore-dir=s' # XXX Combine this version with the negated version below
3752 => sub {
3753 my ( undef, $dir ) = @_;
3754
3755 $dir = App::Ack::remove_dir_sep( $dir );
3756 if ( $dir !~ /^(?:is|match):/ ) {
3757 $dir = 'is:' . $dir;
3758 }
3759 push @{ $opt->{idirs} }, $dir;
3760 },
3761 'ignore-file=s' => sub {
3762 my ( undef, $file ) = @_;
3763 push @{ $opt->{ifiles} }, $file;
3764 },
3765 'lines=s' => sub { shift; my $val = shift; push @{$opt->{lines}}, $val },
3766 'l|files-with-matches'
3767 => \$opt->{l},
3768 'L|files-without-matches'
3769 => \$opt->{L},
3770 'm|max-count=i' => \$opt->{m},
3771 'match=s' => \$opt->{regex},
3772 'n|no-recurse' => \$opt->{n},
3773 o => sub { $opt->{output} = '$&' },
3774 'output=s' => \$opt->{output},
3775 'pager=s' => \$opt->{pager},
3776 'noignore-directory|noignore-dir=s'
3777 => sub {
3778 my ( undef, $dir ) = @_;
3779
3780 # XXX can you do --noignore-dir=match,...?
3781 $dir = App::Ack::remove_dir_sep( $dir );
3782 if ( $dir !~ /^(?:is|match):/ ) {
3783 $dir = 'is:' . $dir;
3784 }
3785 if ( $dir !~ /^(?:is|match):/ ) {
3786 Carp::croak("invalid noignore-directory argument: '$dir'");
3787 }
3788
3789 @{ $opt->{idirs} } = grep {
3790 $_ ne $dir
3791 } @{ $opt->{idirs} };
3792
3793 push @{ $opt->{no_ignore_dirs} }, $dir;
3794 },
3795 'nopager' => sub { $opt->{pager} = undef },
3796 'passthru' => \$opt->{passthru},
3797 'print0' => \$opt->{print0},
3798 'Q|literal' => \$opt->{Q},
3799 'r|R|recurse' => sub { $opt->{n} = 0 },
3800 's' => \$opt->{dont_report_bad_filenames},
3801 'show-types' => \$opt->{show_types},
3802 'smart-case!' => \$opt->{smart_case},
3803 'sort-files' => \$opt->{sort_files},
3804 'type=s' => sub {
3805 my ( $getopt, $value ) = @_;
3806
3807 my $cb_value = 1;
3808 if ( $value =~ s/^no// ) {
3809 $cb_value = 0;
3810 }
3811
3812 my $callback = $extra_specs->{ $value . '!' };
3813
3814 if ( $callback ) {
3815 $callback->( $getopt, $cb_value );
3816 }
3817 else {
3818 Carp::croak( "Unknown type '$value'" );
3819 }
3820 },
3821 'u' => removed_option('-u'),
3822 'unrestricted' => removed_option('--unrestricted'),
3823 'v|invert-match' => \$opt->{v},
3824 'w|word-regexp' => \$opt->{w},
3825 'x' => sub { $opt->{files_from} = '-' },
3826
3827 'version' => sub { App::Ack::print_version_statement(); exit; },
3828 'help|?:s' => sub { shift; App::Ack::show_help(@_); exit; },
3829 'help-types' => sub { App::Ack::show_help_types(); exit; },
3830 'man' => sub { App::Ack::show_man(); exit; },
3831 $extra_specs ? %{$extra_specs} : (),
3832 }; # arg_specs
3833 }
3834
3835 sub process_other {
3836 my ( $opt, $extra_specs, $arg_sources ) = @_;
3837
3838 Getopt::Long::Configure('default', 'no_auto_help', 'no_auto_version'); # start with default options, minus some annoying ones
3839 Getopt::Long::Configure(
3840 'bundling',
3841 'no_ignore_case',
3842 );
3843
3844 my $argv_source;
3845 my $is_help_types_active;
3846
3847 for ( my $i = 0; $i < @{$arg_sources}; $i += 2 ) {
3848 my ( $source_name, $args ) = @{$arg_sources}[ $i, $i + 1 ];
3849
3850 if ( $source_name eq 'ARGV' ) {
3851 $argv_source = $args;
3852 last;
3853 }
3854 }
3855
3856 if ( $argv_source ) { # this *should* always be true, but you never know...
3857 my @copy = @{$argv_source};
3858
3859 Getopt::Long::Configure('pass_through');
3860
3861 Getopt::Long::GetOptionsFromArray( \@copy,
3862 'help-types' => \$is_help_types_active,
3863 );
3864
3865 Getopt::Long::Configure('no_pass_through');
3866 }
3867
3868 my $arg_specs = get_arg_spec($opt, $extra_specs);
3869
3870 for ( my $i = 0; $i < @{$arg_sources}; $i += 2) {
3871 my ($source_name, $args) = @{$arg_sources}[$i, $i + 1];
3872
3873 my $ret;
3874 if ( ref($args) ) {
3875 $ret = Getopt::Long::GetOptionsFromArray( $args, %{$arg_specs} );
3876 }
3877 else {
3878 ( $ret, $arg_sources->[$i + 1] ) =
3879 Getopt::Long::GetOptionsFromString( $args, %{$arg_specs} );
3880 }
3881 if ( !$ret ) {
3882 if ( !$is_help_types_active ) {
3883 my $where = $source_name eq 'ARGV' ? 'on command line' : "in $source_name";
3884 App::Ack::die( "Invalid option $where" );
3885 }
3886 }
3887 if ( $opt->{noenv_seen} ) {
3888 App::Ack::die( "--noenv found in $source_name" );
3889 }
3890 }
3891
3892 # XXX We need to check on a -- in the middle of a non-ARGV source
3893
3894 return;
3895 }
3896
3897 sub should_dump_options {
3898 my ( $sources ) = @_;
3899
3900 for(my $i = 0; $i < @{$sources}; $i += 2) {
3901 my ( $name, $options ) = @{$sources}[$i, $i + 1];
3902 if($name eq 'ARGV') {
3903 my $dump;
3904 Getopt::Long::Configure('default', 'pass_through', 'no_auto_help', 'no_auto_version');
3905 Getopt::Long::GetOptionsFromArray($options,
3906 'dump' => \$dump,
3907 );
3908 return $dump;
3909 }
3910 }
3911 return;
3912 }
3913
3914 sub explode_sources {
3915 my ( $sources ) = @_;
3916
3917 my @new_sources;
3918
3919 Getopt::Long::Configure('default', 'pass_through', 'no_auto_help', 'no_auto_version');
3920
3921 my %opt;
3922 my $arg_spec = get_arg_spec(\%opt);
3923
3924 my $add_type = sub {
3925 my ( undef, $arg ) = @_;
3926
3927 # XXX refactor?
3928 if ( $arg =~ /(\w+)=/) {
3929 $arg_spec->{$1} = sub {};
3930 }
3931 else {
3932 ( $arg ) = split /:/, $arg;
3933 $arg_spec->{$arg} = sub {};
3934 }
3935 };
3936
3937 my $del_type = sub {
3938 my ( undef, $arg ) = @_;
3939
3940 delete $arg_spec->{$arg};
3941 };
3942
3943 for(my $i = 0; $i < @{$sources}; $i += 2) {
3944 my ( $name, $options ) = @{$sources}[$i, $i + 1];
3945 if ( ref($options) ne 'ARRAY' ) {
3946 $sources->[$i + 1] = $options =
3947 [ Text::ParseWords::shellwords($options) ];
3948 }
3949 for ( my $j = 0; $j < @{$options}; $j++ ) {
3950 next unless $options->[$j] =~ /^-/;
3951 my @chunk = ( $options->[$j] );
3952 push @chunk, $options->[$j] while ++$j < @{$options} && $options->[$j] !~ /^-/;
3953 $j--;
3954
3955 my @copy = @chunk;
3956 Getopt::Long::GetOptionsFromArray(\@chunk,
3957 'type-add=s' => $add_type,
3958 'type-set=s' => $add_type,
3959 'type-del=s' => $del_type,
3960 );
3961 Getopt::Long::GetOptionsFromArray(\@chunk, %{$arg_spec});
3962
3963 splice @copy, -1 * @chunk if @chunk; # XXX explain this
3964 push @new_sources, $name, \@copy;
3965 }
3966 }
3967
3968 return \@new_sources;
3969 }
3970
3971 sub compare_opts {
3972 my ( $a, $b ) = @_;
3973
3974 my $first_a = $a->[0];
3975 my $first_b = $b->[0];
3976
3977 $first_a =~ s/^--?//;
3978 $first_b =~ s/^--?//;
3979
3980 return $first_a cmp $first_b;
3981 }
3982
3983 sub dump_options {
3984 my ( $sources ) = @_;
3985
3986 $sources = explode_sources($sources);
3987
3988 my %opts_by_source;
3989 my @source_names;
3990
3991 for(my $i = 0; $i < @{$sources}; $i += 2) {
3992 my ( $name, $contents ) = @{$sources}[$i, $i + 1];
3993 if ( not $opts_by_source{$name} ) {
3994 $opts_by_source{$name} = [];
3995 push @source_names, $name;
3996 }
3997 push @{$opts_by_source{$name}}, $contents;
3998 }
3999
4000 foreach my $name (@source_names) {
4001 my $contents = $opts_by_source{$name};
4002
4003 print $name, "\n";
4004 print '=' x length($name), "\n";
4005 print ' ', join(' ', @{$_}), "\n" foreach sort { compare_opts($a, $b) } @{$contents};
4006 }
4007
4008 return;
4009 }
4010
4011 sub remove_default_options_if_needed {
4012 my ( $sources ) = @_;
4013
4014 my $default_index;
4015
4016 foreach my $index ( 0 .. $#$sources ) {
4017 if ( $sources->[$index] eq 'Defaults' ) {
4018 $default_index = $index;
4019 last;
4020 }
4021 }
4022
4023 return $sources unless defined $default_index;
4024
4025 my $should_remove = 0;
4026
4027 Getopt::Long::Configure('default', 'no_auto_help', 'no_auto_version'); # start with default options, minus some annoying ones
4028 Getopt::Long::Configure(
4029 'no_ignore_case',
4030 'no_auto_abbrev',
4031 'pass_through',
4032 );
4033
4034 foreach my $index ( $default_index + 2 .. $#$sources ) {
4035 next if $index % 2 != 0;
4036
4037 my ( $name, $args ) = @{$sources}[ $index, $index + 1 ];
4038
4039 if (ref($args)) {
4040 Getopt::Long::GetOptionsFromArray($args,
4041 'ignore-ack-defaults' => \$should_remove,
4042 );
4043 }
4044 else {
4045 ( undef, $sources->[$index + 1] ) = Getopt::Long::GetOptionsFromString($args,
4046 'ignore-ack-defaults' => \$should_remove,
4047 );
4048 }
4049 }
4050
4051 Getopt::Long::Configure('default');
4052 Getopt::Long::Configure('default', 'no_auto_help', 'no_auto_version');
4053
4054 return $sources unless $should_remove;
4055
4056 my @copy = @{$sources};
4057 splice @copy, $default_index, 2;
4058 return \@copy;
4059 }
4060
4061 sub check_for_mutually_exclusive_options {
4062 my ( $arg_sources ) = @_;
4063
4064 my %mutually_exclusive_with;
4065 my @copy = @{$arg_sources};
4066
4067 for(my $i = 0; $i < @INVALID_COMBINATIONS; $i += 2) {
4068 my ( $lhs, $rhs ) = @INVALID_COMBINATIONS[ $i, $i + 1 ];
4069
4070 foreach my $l_opt ( @{$lhs} ) {
4071 foreach my $r_opt ( @{$rhs} ) {
4072 push @{ $mutually_exclusive_with{ $l_opt } }, $r_opt;
4073 push @{ $mutually_exclusive_with{ $r_opt } }, $l_opt;
4074 }
4075 }
4076 }
4077
4078 while( @copy ) {
4079 my %set_opts;
4080
4081 my ( $source_name, $args ) = splice @copy, 0, 2;
4082 $args = ref($args) ? [ @{$args} ] : [ Text::ParseWords::shellwords($args) ];
4083
4084 foreach my $opt ( @{$args} ) {
4085 next unless $opt =~ /^[-+]/;
4086 last if $opt eq '--';
4087
4088 if( $opt =~ /^(.*)=/ ) {
4089 $opt = $1;
4090 }
4091 elsif ( $opt =~ /^(-[^-]).+/ ) {
4092 $opt = $1;
4093 }
4094
4095 $set_opts{ $opt } = 1;
4096
4097 my $mutex_opts = $mutually_exclusive_with{ $opt };
4098
4099 next unless $mutex_opts;
4100
4101 foreach my $mutex_opt ( @{$mutex_opts} ) {
4102 if($set_opts{ $mutex_opt }) {
4103 die "Options '$mutex_opt' and '$opt' are mutually exclusive\n";
4104 }
4105 }
4106 }
4107 }
4108 }
4109
4110 sub process_args {
4111 my $arg_sources = \@_;
4112
4113 my %opt;
4114
4115 check_for_mutually_exclusive_options($arg_sources);
4116
4117 $arg_sources = remove_default_options_if_needed($arg_sources);
4118
4119 if ( should_dump_options($arg_sources) ) {
4120 dump_options($arg_sources);
4121 exit(0);
4122 }
4123
4124 my $type_specs = process_filetypes(\%opt, $arg_sources);
4125 process_other(\%opt, $type_specs, $arg_sources);
4126 while ( @{$arg_sources} ) {
4127 my ( $source_name, $args ) = splice( @{$arg_sources}, 0, 2 );
4128
4129 # All of our sources should be transformed into an array ref
4130 if ( ref($args) ) {
4131 if ( $source_name eq 'ARGV' ) {
4132 @ARGV = @{$args};
4133 }
4134 elsif (@{$args}) {
4135 Carp::croak "source '$source_name' has extra arguments!";
4136 }
4137 }
4138 else {
4139 Carp::croak 'The impossible has occurred!';
4140 }
4141 }
4142 my $filters = ($opt{filters} ||= []);
4143
4144 # throw the default filter in if no others are selected
4145 if ( not grep { !$_->is_inverted() } @{$filters} ) {
4146 push @{$filters}, App::Ack::Filter::Default->new();
4147 }
4148 return \%opt;
4149 }
4150
4151 1; # End of App::Ack::ConfigLoader
4152 package App::Ack::ConfigDefault;
4153
4154 use warnings;
4155 use strict;
4156
4157 sub options {
4158 my @options = split( /\n/, _options_block() );
4159 @options = grep { /./ && !/^#/ } @options;
4160
4161 return @options;
4162 }
4163
4164 sub _options_block {
4165 return <<'HERE';
4166 # This is the default ackrc for ack 2.0
4167
4168 # There are four different ways to match
4169 #
4170 # is: Match the filename exactly
4171 #
4172 # ext: Match the extension of the filename exactly
4173 #
4174 # match: Match the filename against a Perl regular expression
4175 #
4176 # firstlinematch: Match the first 250 characters of the first line
4177 # of text against a Perl regular expression. This is only for
4178 # the --type-add option.
4179
4180
4181 # Directories to ignore
4182 # Bazaar
4183 --ignore-directory=is:.bzr
4184
4185 # Codeville
4186 --ignore-directory=is:.cdv
4187
4188 # Interface Builder
4189 --ignore-directory=is:~.dep
4190 --ignore-directory=is:~.dot
4191 --ignore-directory=is:~.nib
4192 --ignore-directory=is:~.plst
4193
4194 # Git
4195 --ignore-directory=is:.git
4196
4197 # Mercurial
4198 --ignore-directory=is:.hg
4199
4200 # quilt
4201 --ignore-directory=is:.pc
4202
4203 # Subversion
4204 --ignore-directory=is:.svn
4205
4206 # Monotone
4207 --ignore-directory=is:_MTN
4208
4209 # CVS
4210 --ignore-directory=is:CVS
4211
4212 # RCS
4213 --ignore-directory=is:RCS
4214
4215 # SCCS
4216 --ignore-directory=is:SCCS
4217
4218 # darcs
4219 --ignore-directory=is:_darcs
4220
4221 # Vault/Fortress
4222 --ignore-directory=is:_sgbak
4223
4224 # autoconf
4225 --ignore-directory=is:autom4te.cache
4226
4227 # Perl module building
4228 --ignore-directory=is:blib
4229 --ignore-directory=is:_build
4230
4231 # Perl Devel::Cover module's output directory
4232 --ignore-directory=is:cover_db
4233
4234
4235
4236 # Files to ignore
4237 # Backup files
4238 --ignore-file=ext:bak
4239 --ignore-file=match:/~$/
4240
4241 # Emacs swap files
4242 --ignore-file=match:/^#.+#$/
4243
4244 # vi/vim swap files
4245 --ignore-file=match:/[._].*\.swp$/
4246
4247 # core dumps
4248 --ignore-file=match:/core\.\d+$/
4249
4250 # minified Javascript
4251 --ignore-file=match:/[.]min[.]js$/
4252
4253
4254 # Filetypes defined
4255
4256 # Perl http://perl.org/
4257 --type-add=perl:ext:pl,pm,pod,t
4258 --type-add=perl:firstlinematch:/^#!.*\bperl/
4259
4260 # Makefiles http://www.gnu.org/s/make/
4261 --type-add=make:ext:mk
4262 --type-add=make:ext:mak
4263 --type-add=make:is:makefile
4264 --type-add=make:is:Makefile
4265 --type-add=make:is:GNUmakefile
4266
4267 # Rakefiles http://rake.rubyforge.org/
4268 --type-add=rake:is:Rakefile
4269
4270 # CMake http://www.cmake.org/
4271 --type-add=cmake:is:CMakeLists.txt
4272 --type-add=cmake:ext:cmake
4273
4274 # Actionscript
4275 --type-add=actionscript:ext:as,mxml
4276
4277 # Ada http://www.adaic.org/
4278 --type-add=ada:ext:ada,adb,ads
4279
4280 # ASP http://msdn.microsoft.com/en-us/library/aa286483.aspx
4281 --type-add=asp:ext:asp
4282
4283 # ASP.Net http://www.asp.net/
4284 --type-add=aspx:ext:master,ascx,asmx,aspx,svc
4285
4286 # Assembly
4287 --type-add=asm:ext:asm,s
4288
4289 # Batch
4290 --type-add=batch:ext:bat,cmd
4291
4292 # ColdFusion http://en.wikipedia.org/wiki/ColdFusion
4293 --type-add=cfmx:ext:cfc,cfm,cfml
4294
4295 # Clojure http://clojure.org/
4296 --type-add=clojure:ext:clj
4297
4298 # C
4299 # .xs are Perl C files
4300 --type-add=cc:ext:c,h,xs
4301
4302 # C header files
4303 --type-add=hh:ext:h
4304
4305 # C++
4306 --type-add=cpp:ext:cpp,cc,cxx,m,hpp,hh,h,hxx
4307
4308 # C#
4309 --type-add=csharp:ext:cs
4310
4311 # CSS http://www.w3.org/Style/CSS/
4312 --type-add=css:ext:css
4313
4314 # Delphi http://en.wikipedia.org/wiki/Embarcadero_Delphi
4315 --type-add=delphi:ext:pas,int,dfm,nfm,dof,dpk,dproj,groupproj,bdsgroup,bdsproj
4316
4317 # Emacs Lisp http://www.gnu.org/software/emacs
4318 --type-add=elisp:ext:el
4319
4320 # Erlang http://www.erlang.org/
4321 --type-add=erlang:ext:erl,hrl
4322
4323 # Fortran http://en.wikipedia.org/wiki/Fortran
4324 --type-add=fortran:ext:f,f77,f90,f95,f03,for,ftn,fpp
4325
4326 # Google Go http://golang.org/
4327 --type-add=go:ext:go
4328
4329 # Groovy http://groovy.codehaus.org/
4330 --type-add=groovy:ext:groovy,gtmpl,gpp,grunit,gradle
4331
4332 # Haskell http://www.haskell.org/
4333 --type-add=haskell:ext:hs,lhs
4334
4335 # HTML
4336 --type-add=html:ext:htm,html
4337
4338 # Java http://www.oracle.com/technetwork/java/index.html
4339 --type-add=java:ext:java,properties
4340
4341 # JavaScript
4342 --type-add=js:ext:js
4343
4344 # JSP http://www.oracle.com/technetwork/java/javaee/jsp/index.html
4345 --type-add=jsp:ext:jsp,jspx,jhtm,jhtml
4346
4347 # Common Lisp http://common-lisp.net/
4348 --type-add=lisp:ext:lisp,lsp
4349
4350 # Lua http://www.lua.org/
4351 --type-add=lua:ext:lua
4352
4353 # Objective-C
4354 --type-add=objc:ext:m,h
4355
4356 # Objective-C++
4357 --type-add=objcpp:ext:mm,h
4358
4359 # OCaml http://caml.inria.fr/
4360 --type-add=ocaml:ext:ml,mli
4361
4362 # Parrot http://www.parrot.org/
4363 --type-add=parrot:ext:pir,pasm,pmc,ops,pod,pg,tg
4364
4365 # PHP http://www.php.net/
4366 --type-add=php:ext:php,phpt,php3,php4,php5,phtml
4367 --type-add=php:firstlinematch:/^#!.*\bphp/
4368
4369 # Plone http://plone.org/
4370 --type-add=plone:ext:pt,cpt,metadata,cpy,py
4371
4372 # Python http://www.python.org/
4373 --type-add=python:ext:py
4374 --type-add=python:firstlinematch:/^#!.*\bpython/
4375
4376 # R http://www.r-project.org/
4377 --type-add=rr:ext:R
4378
4379 # Ruby http://www.ruby-lang.org/
4380 --type-add=ruby:ext:rb,rhtml,rjs,rxml,erb,rake,spec
4381 --type-add=ruby:is:Rakefile
4382 --type-add=ruby:firstlinematch:/^#!.*\bruby/
4383
4384 # Rust http://www.rust-lang.org/
4385 --type-add=rust:ext:rs
4386
4387 # Scala http://www.scala-lang.org/
4388 --type-add=scala:ext:scala
4389
4390 # Scheme http://groups.csail.mit.edu/mac/projects/scheme/
4391 --type-add=scheme:ext:scm,ss
4392
4393 # Shell
4394 --type-add=shell:ext:sh,bash,csh,tcsh,ksh,zsh
4395 --type-add=shell:firstlinematch:/^#!.*\b(?:ba|t?c|k|z)?sh\b/
4396
4397 # Smalltalk http://www.smalltalk.org/
4398 --type-add=smalltalk:ext:st
4399
4400 # SQL http://www.iso.org/iso/catalogue_detail.htm?csnumber=45498
4401 --type-add=sql:ext:sql,ctl
4402
4403 # Tcl http://www.tcl.tk/
4404 --type-add=tcl:ext:tcl,itcl,itk
4405
4406 # LaTeX http://www.latex-project.org/
4407 --type-add=tex:ext:tex,cls,sty
4408
4409 # Template Toolkit http://template-toolkit.org/
4410 --type-add=tt:ext:tt,tt2,ttml
4411
4412 # Visual Basic
4413 --type-add=vb:ext:bas,cls,frm,ctl,vb,resx
4414
4415 # Verilog
4416 --type-add=verilog:ext:v,vh,sv
4417
4418 # VHDL http://www.eda.org/twiki/bin/view.cgi/P1076/WebHome
4419 --type-add=vhdl:ext:vhd,vhdl
4420
4421 # Vim http://www.vim.org/
4422 --type-add=vim:ext:vim
4423
4424 # XML http://www.w3.org/TR/REC-xml/
4425 --type-add=xml:ext:xml,dtd,xsl,xslt,ent
4426 --type-add=xml:firstlinematch:/<[?]xml/
4427
4428 # YAML http://yaml.org/
4429 --type-add=yaml:ext:yaml,yml
4430 HERE
4431 }
4432
4433 1;