Lib/unicode/: Add all files from <ftp://ftp.unicode.org/Public/12.1.0/>
[sunny256-utils.git] / ack
blob59105037c5846e199a51a975393921e47e2246b4
1 #!/usr/bin/env perl
3 # This file, ack, is generated code.
4 # Please DO NOT EDIT or send patches for it.
6 # Please take a look at the source from
7 # https://github.com/petdance/ack2
8 # and submit patches against the individual files
9 # that build ack.
12 package main;
14 use strict;
15 use warnings;
17 our $VERSION = '2.14'; # Check http://beyondgrep.com/ for updates
19 use 5.008008;
20 use Getopt::Long 2.35 ();
21 use Carp 1.04 ();
23 use File::Spec ();
26 # XXX Don't make this so brute force
27 # See also: https://github.com/petdance/ack2/issues/89
29 # These are all our globals.
31 MAIN: {
32 $App::Ack::orig_program_name = $0;
33 $0 = join(' ', 'ack', $0);
34 if ( $App::Ack::VERSION ne $main::VERSION ) {
35 App::Ack::die( "Program/library version mismatch\n\t$0 is $main::VERSION\n\t$INC{'App/Ack.pm'} is $App::Ack::VERSION" );
38 # Do preliminary arg checking;
39 my $env_is_usable = 1;
40 for my $arg ( @ARGV ) {
41 last if ( $arg eq '--' );
43 # Get the --thpppt, --bar, --cathy checking out of the way.
44 $arg =~ /^--th[pt]+t+$/ and App::Ack::_thpppt($arg);
45 $arg eq '--bar' and App::Ack::_bar();
46 $arg eq '--cathy' and App::Ack::_cathy();
48 # See if we want to ignore the environment. (Don't tell Al Gore.)
49 $arg eq '--env' and $env_is_usable = 1;
50 $arg eq '--noenv' and $env_is_usable = 0;
53 if ( !$env_is_usable ) {
54 my @keys = ( 'ACKRC', grep { /^ACK_/ } keys %ENV );
55 delete @ENV{@keys};
57 load_colors();
59 Getopt::Long::Configure('default', 'no_auto_help', 'no_auto_version');
60 Getopt::Long::Configure('pass_through', 'no_auto_abbrev');
61 Getopt::Long::GetOptions(
62 'help' => sub { App::Ack::show_help(); exit; },
63 'version' => sub { App::Ack::print_version_statement(); exit; },
64 'man' => sub { App::Ack::show_man(); exit; },
66 Getopt::Long::Configure('default', 'no_auto_help', 'no_auto_version');
68 if ( !@ARGV ) {
69 App::Ack::show_help();
70 exit 1;
73 main();
76 sub _compile_descend_filter {
77 my ( $opt ) = @_;
79 my $idirs = $opt->{idirs};
80 my $dont_ignore_dirs = $opt->{no_ignore_dirs};
82 # if we have one or more --noignore-dir directives, we can't ignore
83 # entire subdirectory hierarchies, so we return an "accept all"
84 # filter and scrutinize the files more in _compile_file_filter
85 return if $dont_ignore_dirs;
86 return unless $idirs && @{$idirs};
88 my %ignore_dirs;
90 foreach my $idir (@{$idirs}) {
91 if ( $idir =~ /^(\w+):(.*)/ ) {
92 if ( $1 eq 'is') {
93 $ignore_dirs{$2} = 1;
95 else {
96 Carp::croak( 'Non-is filters are not yet supported for --ignore-dir' );
99 else {
100 Carp::croak( qq{Invalid filter specification "$idir"} );
104 return sub {
105 return !exists $ignore_dirs{$_} && !exists $ignore_dirs{$File::Next::dir};
109 sub _compile_file_filter {
110 my ( $opt, $start ) = @_;
112 my $ifiles = $opt->{ifiles};
113 $ifiles ||= [];
115 my $ifiles_filters = App::Ack::Filter::Collection->new();
117 foreach my $filter_spec (@{$ifiles}) {
118 if ( $filter_spec =~ /^(\w+):(.+)/ ) {
119 my ($how,$what) = ($1,$2);
120 my $filter = App::Ack::Filter->create_filter($how, split(/,/, $what));
121 $ifiles_filters->add($filter);
123 else {
124 Carp::croak( qq{Invalid filter specification "$filter_spec"} );
128 my $filters = $opt->{'filters'} || [];
129 my $direct_filters = App::Ack::Filter::Collection->new();
130 my $inverse_filters = App::Ack::Filter::Collection->new();
132 foreach my $filter (@{$filters}) {
133 if ($filter->is_inverted()) {
134 # We want to check if files match the uninverted filters
135 $inverse_filters->add($filter->invert());
137 else {
138 $direct_filters->add($filter);
142 my %is_member_of_starting_set = map { (get_file_id($_) => 1) } @{$start};
144 my $ignore_dir_list = $opt->{idirs};
145 my $dont_ignore_dir_list = $opt->{no_ignore_dirs};
147 my %ignore_dir_set;
148 my %dont_ignore_dir_set;
150 foreach my $filter (@{ $ignore_dir_list }) {
151 if ( $filter =~ /^(\w+):(.*)/ ) {
152 if ( $1 eq 'is' ) {
153 $ignore_dir_set{ $2 } = 1;
154 } else {
155 Carp::croak( 'Non-is filters are not yet supported for --ignore-dir' );
157 } else {
158 Carp::croak( qq{Invalid filter specification "$filter"} );
161 foreach my $filter (@{ $dont_ignore_dir_list }) {
162 if ( $filter =~ /^(\w+):(.*)/ ) {
163 if ( $1 eq 'is' ) {
164 $dont_ignore_dir_set{ $2 } = 1;
165 } else {
166 Carp::croak( 'Non-is filters are not yet supported for --ignore-dir' );
168 } else {
169 Carp::croak( qq{Invalid filter specification "$filter"} );
173 my $match_filenames = $opt->{g};
174 my $match_regex = $opt->{regex};
175 my $is_inverted = $opt->{v};
177 return sub {
178 if ( $match_filenames ) {
179 if ( $File::Next::name =~ /$match_regex/ && $is_inverted ) {
180 return;
182 if ( $File::Next::name !~ /$match_regex/ && !$is_inverted ) {
183 return;
186 # ack always selects files that are specified on the command
187 # line, regardless of filetype. If you want to ack a JPEG,
188 # and say "ack foo whatever.jpg" it will do it for you.
189 return 1 if $is_member_of_starting_set{ get_file_id($File::Next::name) };
191 if ( $dont_ignore_dir_list ) {
192 my ( undef, $dirname ) = File::Spec->splitpath($File::Next::name);
193 my @dirs = File::Spec->splitdir($dirname);
195 my $is_ignoring = 0;
197 foreach my $dir ( @dirs ) {
198 if ( $ignore_dir_set{ $dir } ) {
199 $is_ignoring = 1;
201 elsif ( $dont_ignore_dir_set{ $dir } ) {
202 $is_ignoring = 0;
205 if ( $is_ignoring ) {
206 return 0;
210 # Ignore named pipes found in directory searching. Named
211 # pipes created by subprocesses get specified on the command
212 # line, so the rule of "always select whatever is on the
213 # command line" wins.
214 return 0 if -p $File::Next::name;
216 # We can't handle unreadable filenames; report them.
217 if ( not -r _ ) {
218 use filetest 'access';
220 if ( not -R $File::Next::name ) {
221 if ( $App::Ack::report_bad_filenames ) {
222 App::Ack::warn( "${File::Next::name}: cannot open file for reading" );
224 return 0;
228 my $resource = App::Ack::Resource::Basic->new($File::Next::name);
229 return 0 if !$resource || $ifiles_filters->filter($resource);
231 my $match_found = $direct_filters->filter($resource);
233 # Don't bother invoking inverse filters unless we consider the current resource a match
234 if ( $match_found && $inverse_filters->filter( $resource ) ) {
235 $match_found = 0;
237 return $match_found;
241 sub show_types {
242 my $resource = shift;
243 my $ors = shift;
245 my @types = filetypes( $resource );
246 my $types = join( ',', @types );
247 my $arrow = @types ? ' => ' : ' =>';
248 App::Ack::print( $resource->name, $arrow, join( ',', @types ), $ors );
250 return;
253 # Set default colors, load Term::ANSIColor
254 sub load_colors {
255 eval 'use Term::ANSIColor 1.10 ()';
256 eval 'use Win32::Console::ANSI' if $App::Ack::is_windows;
258 $ENV{ACK_COLOR_MATCH} ||= 'black on_yellow';
259 $ENV{ACK_COLOR_FILENAME} ||= 'bold green';
260 $ENV{ACK_COLOR_LINENO} ||= 'bold yellow';
262 return;
265 sub filetypes {
266 my ( $resource ) = @_;
268 my @matches;
270 foreach my $k (keys %App::Ack::mappings) {
271 my $filters = $App::Ack::mappings{$k};
273 foreach my $filter (@{$filters}) {
274 # clone the resource
275 my $clone = $resource->clone;
276 if ( $filter->filter($clone) ) {
277 push @matches, $k;
278 last;
283 # http://search.cpan.org/dist/Perl-Critic/lib/Perl/Critic/Policy/Subroutines/ProhibitReturnSort.pm
284 @matches = sort @matches;
285 return @matches;
288 # Returns a (fairly) unique identifier for a file.
289 # Use this function to compare two files to see if they're
290 # equal (ie. the same file, but with a different path/links/etc).
291 sub get_file_id {
292 my ( $filename ) = @_;
294 if ( $App::Ack::is_windows ) {
295 return File::Next::reslash( $filename );
297 else {
298 # XXX is this the best method? it always hits the FS
299 if( my ( $dev, $inode ) = (stat($filename))[0, 1] ) {
300 return join(':', $dev, $inode);
302 else {
303 # XXX this could be better
304 return $filename;
309 # Returns a regex object based on a string and command-line options.
310 # Dies when the regex $str is undefined (i.e. not given on command line).
312 sub build_regex {
313 my $str = shift;
314 my $opt = shift;
316 defined $str or App::Ack::die( 'No regular expression found.' );
318 $str = quotemeta( $str ) if $opt->{Q};
319 if ( $opt->{w} ) {
320 my $pristine_str = $str;
322 $str = "(?:$str)";
323 $str = "\\b$str" if $pristine_str =~ /^\w/;
324 $str = "$str\\b" if $pristine_str =~ /\w$/;
327 my $regex_is_lc = $str eq lc $str;
328 if ( $opt->{i} || ($opt->{smart_case} && $regex_is_lc) ) {
329 $str = "(?i)$str";
332 my $re = eval { qr/$str/ };
333 if ( !$re ) {
334 die "Invalid regex '$str':\n $@";
337 return $re;
343 my @before_ctx_lines;
344 my @after_ctx_lines;
345 my $is_iterating;
347 my $has_printed_something;
349 BEGIN {
350 $has_printed_something = 0;
353 sub print_matches_in_resource {
354 my ( $resource, $opt ) = @_;
356 my $passthru = $opt->{passthru};
357 my $max_count = $opt->{m} || -1;
358 my $nmatches = 0;
359 my $filename = $resource->name;
360 my $break = $opt->{break};
361 my $heading = $opt->{heading};
362 my $ors = $opt->{print0} ? "\0" : "\n";
363 my $color = $opt->{color};
364 my $print_filename = $opt->{show_filename};
366 my $has_printed_for_this_resource = 0;
368 $is_iterating = 1;
370 local $opt->{before_context} = $opt->{output} ? 0 : $opt->{before_context};
371 local $opt->{after_context} = $opt->{output} ? 0 : $opt->{after_context};
373 my $n_before_ctx_lines = $opt->{before_context} || 0;
374 my $n_after_ctx_lines = $opt->{after_context} || 0;
376 @after_ctx_lines = @before_ctx_lines = ();
378 my $fh = $resource->open();
379 if ( !$fh ) {
380 if ( $App::Ack::report_bad_filenames ) {
381 App::Ack::warn( "$filename: $!" );
383 return 0;
386 my $display_filename = $filename;
387 if ( $print_filename && $heading && $color ) {
388 $display_filename = Term::ANSIColor::colored($display_filename, $ENV{ACK_COLOR_FILENAME});
391 # check for context before the main loop, so we don't
392 # pay for it if we don't need it
393 if ( $n_before_ctx_lines || $n_after_ctx_lines ) {
394 my $current_line = <$fh>; # prime the first line of input
396 while ( defined $current_line ) {
397 while ( (@after_ctx_lines < $n_after_ctx_lines) && defined($_ = <$fh>) ) {
398 push @after_ctx_lines, $_;
401 local $_ = $current_line;
402 my $former_dot_period = $.;
403 $. -= @after_ctx_lines;
405 if ( does_match($opt, $_) ) {
406 if ( !$has_printed_for_this_resource ) {
407 if ( $break && $has_printed_something ) {
408 App::Ack::print_blank_line();
410 if ( $print_filename && $heading ) {
411 App::Ack::print_filename( $display_filename, $ors );
414 print_line_with_context($opt, $filename, $_, $.);
415 $has_printed_for_this_resource = 1;
416 $nmatches++;
417 $max_count--;
419 elsif ( $passthru ) {
420 chomp; # XXX proper newline handling?
421 # XXX inline this call?
422 if ( $break && !$has_printed_for_this_resource && $has_printed_something ) {
423 App::Ack::print_blank_line();
425 print_line_with_options($opt, $filename, $_, $., ':');
426 $has_printed_for_this_resource = 1;
428 last unless $max_count != 0;
430 # I tried doing this with local(), but for some reason,
431 # $. continued to have its new value after the exit of the
432 # enclosing block. I'm guessing that $. has some extra
433 # magic associated with it or something. If someone can
434 # tell me why this happened, I would love to know!
435 $. = $former_dot_period; # XXX this won't happen on an exception
437 if ( $n_before_ctx_lines ) {
438 push @before_ctx_lines, $current_line;
439 shift @before_ctx_lines while @before_ctx_lines > $n_before_ctx_lines;
441 if ( $n_after_ctx_lines ) {
442 $current_line = shift @after_ctx_lines;
444 else {
445 $current_line = <$fh>;
449 else {
450 local $_;
452 while ( <$fh> ) {
453 if ( does_match($opt, $_) ) {
454 if ( !$has_printed_for_this_resource ) {
455 if ( $break && $has_printed_something ) {
456 App::Ack::print_blank_line();
458 if ( $print_filename && $heading ) {
459 App::Ack::print_filename( $display_filename, $ors );
462 print_line_with_context($opt, $filename, $_, $.);
463 $has_printed_for_this_resource = 1;
464 $nmatches++;
465 $max_count--;
467 elsif ( $passthru ) {
468 chomp; # XXX proper newline handling?
469 if ( $break && !$has_printed_for_this_resource && $has_printed_something ) {
470 App::Ack::print_blank_line();
472 print_line_with_options($opt, $filename, $_, $., ':');
473 $has_printed_for_this_resource = 1;
475 last unless $max_count != 0;
479 $is_iterating = 0; # XXX this won't happen on an exception
480 # then again, do we care? ack doesn't really
481 # handle exceptions anyway.
483 return $nmatches;
486 sub print_line_with_options {
487 my ( $opt, $filename, $line, $line_no, $separator ) = @_;
489 $has_printed_something = 1;
491 my $print_filename = $opt->{show_filename};
492 my $print_column = $opt->{column};
493 my $ors = $opt->{print0} ? "\0" : "\n";
494 my $heading = $opt->{heading};
495 my $output_expr = $opt->{output};
496 my $color = $opt->{color};
498 my @line_parts;
500 if( $color ) {
501 $filename = Term::ANSIColor::colored($filename,
502 $ENV{ACK_COLOR_FILENAME});
503 $line_no = Term::ANSIColor::colored($line_no,
504 $ENV{ACK_COLOR_LINENO});
507 if($print_filename) {
508 if( $heading ) {
509 push @line_parts, $line_no;
511 else {
512 push @line_parts, $filename, $line_no;
515 if( $print_column ) {
516 push @line_parts, get_match_column();
519 if( $output_expr ) {
520 while ( $line =~ /$opt->{regex}/og ) {
521 # XXX We need to stop using eval() for --output. See https://github.com/petdance/ack2/issues/421
522 my $output = eval $output_expr;
523 App::Ack::print( join( $separator, @line_parts, $output ), $ors );
526 else {
527 if ( $color ) {
528 $line =~ /$opt->{regex}/o; # this match is redundant, but we need
529 # to perfom it in order to get if
530 # capture groups are set
532 if ( @+ > 1 ) { # if we have captures
533 while ( $line =~ /$opt->{regex}/og ) {
534 my $offset = 0; # additional offset for when we add stuff
535 my $previous_match_end = 0;
537 for ( my $i = 1; $i < @+; $i++ ) {
538 my ( $match_start, $match_end ) = ( $-[$i], $+[$i] );
540 next unless defined($match_start);
541 next if $match_start < $previous_match_end;
543 my $substring = substr( $line,
544 $offset + $match_start, $match_end - $match_start );
545 my $substitution = Term::ANSIColor::colored( $substring,
546 $ENV{ACK_COLOR_MATCH} );
548 substr( $line, $offset + $match_start,
549 $match_end - $match_start, $substitution );
551 $previous_match_end = $match_end; # offsets do not need to be applied
552 $offset += length( $substitution ) - length( $substring );
555 pos($line) = $+[0] + $offset;
558 else {
559 my $matched = 0; # flag; if matched, need to escape afterwards
561 while ( $line =~ /$opt->{regex}/og ) {
563 $matched = 1;
564 my ( $match_start, $match_end ) = ($-[0], $+[0]);
565 next unless defined($match_start);
567 my $substring = substr( $line, $match_start,
568 $match_end - $match_start );
569 my $substitution = Term::ANSIColor::colored( $substring,
570 $ENV{ACK_COLOR_MATCH} );
572 substr( $line, $match_start, $match_end - $match_start,
573 $substitution );
575 pos($line) = $match_end +
576 (length( $substitution ) - length( $substring ));
578 # XXX why do we do this?
579 $line .= "\033[0m\033[K" if $matched;
583 push @line_parts, $line;
584 App::Ack::print( join( $separator, @line_parts ), $ors );
587 return;
590 sub iterate {
591 my ( $resource, $opt, $cb ) = @_;
593 $is_iterating = 1;
595 local $opt->{before_context} = $opt->{output} ? 0 : $opt->{before_context};
596 local $opt->{after_context} = $opt->{output} ? 0 : $opt->{after_context};
598 my $n_before_ctx_lines = $opt->{before_context} || 0;
599 my $n_after_ctx_lines = $opt->{after_context} || 0;
601 @after_ctx_lines = @before_ctx_lines = ();
603 my $fh = $resource->open();
604 if ( !$fh ) {
605 if ( $App::Ack::report_bad_filenames ) {
606 App::Ack::warn( $resource->name . ': ' . $! );
608 return;
611 # Check for context before the main loop, so we don't pay for it if we don't need it.
612 if ( $n_before_ctx_lines || $n_after_ctx_lines ) {
613 my $current_line = <$fh>; # prime the first line of input
615 while ( defined $current_line ) {
616 while ( (@after_ctx_lines < $n_after_ctx_lines) && defined($_ = <$fh>) ) {
617 push @after_ctx_lines, $_;
620 local $_ = $current_line;
621 my $former_dot_period = $.;
622 $. -= @after_ctx_lines;
624 last unless $cb->();
626 # I tried doing this with local(), but for some reason,
627 # $. continued to have its new value after the exit of the
628 # enclosing block. I'm guessing that $. has some extra
629 # magic associated with it or something. If someone can
630 # tell me why this happened, I would love to know!
631 $. = $former_dot_period; # XXX this won't happen on an exception
633 if ( $n_before_ctx_lines ) {
634 push @before_ctx_lines, $current_line;
635 shift @before_ctx_lines while @before_ctx_lines > $n_before_ctx_lines;
637 if ( $n_after_ctx_lines ) {
638 $current_line = shift @after_ctx_lines;
640 else {
641 $current_line = <$fh>;
645 else {
646 local $_;
648 while ( <$fh> ) {
649 last unless $cb->();
653 $is_iterating = 0; # XXX this won't happen on an exception
654 # then again, do we care? ack doesn't really
655 # handle exceptions anyway.
657 return;
660 sub get_context {
661 if ( not $is_iterating ) {
662 Carp::croak( 'get_context() called outside of iterate()' );
665 return (
666 scalar(@before_ctx_lines) ? \@before_ctx_lines : undef,
667 scalar(@after_ctx_lines) ? \@after_ctx_lines : undef,
675 my $is_first_match;
676 my $previous_file_processed;
677 my $previous_line_printed;
679 BEGIN {
680 $is_first_match = 1;
681 $previous_line_printed = -1;
684 sub print_line_with_context {
685 my ( $opt, $filename, $matching_line, $line_no ) = @_;
687 my $heading = $opt->{heading};
689 if( !defined($previous_file_processed) ||
690 $previous_file_processed ne $filename ) {
691 $previous_file_processed = $filename;
692 $previous_line_printed = -1;
694 if( $heading ) {
695 $is_first_match = 1;
699 my $ors = $opt->{print0} ? "\0" : "\n";
700 my $match_word = $opt->{w};
701 my $is_tracking_context = $opt->{after_context} || $opt->{before_context};
702 my $output_expr = $opt->{output};
704 $matching_line =~ s/[\r\n]+$//g;
706 my ( $before_context, $after_context ) = get_context();
708 if ( $before_context ) {
709 my $first_line = $. - @{$before_context};
711 if ( $first_line <= $previous_line_printed ) {
712 splice @{$before_context}, 0, $previous_line_printed - $first_line + 1;
713 $first_line = $. - @{$before_context};
715 if ( @{$before_context} ) {
716 my $offset = @{$before_context};
718 if( !$is_first_match && $previous_line_printed != $first_line - 1 ) {
719 App::Ack::print('--', $ors);
721 foreach my $line (@{$before_context}) {
722 my $context_line_no = $. - $offset;
723 if ( $context_line_no <= $previous_line_printed ) {
724 next;
727 chomp $line;
728 local $opt->{column};
730 print_line_with_options($opt, $filename, $line, $context_line_no, '-');
731 $previous_line_printed = $context_line_no;
732 $offset--;
737 if ( $. > $previous_line_printed ) {
738 if( $is_tracking_context && !$is_first_match && $previous_line_printed != $. - 1 ) {
739 App::Ack::print('--', $ors);
742 print_line_with_options($opt, $filename, $matching_line, $line_no, ':');
743 $previous_line_printed = $.;
746 if($after_context) {
747 my $offset = 1;
748 foreach my $line (@{$after_context}) {
749 # XXX improve this!
750 if ( $previous_line_printed >= $. + $offset ) {
751 $offset++;
752 next;
754 chomp $line;
756 if ( $opt->{regex} && does_match( $opt, $line ) ) {
757 print_line_with_options($opt, $filename, $line, $. + $offset, ':');
759 else {
760 local $opt->{column};
761 print_line_with_options($opt, $filename, $line, $. + $offset, '-');
763 $previous_line_printed = $. + $offset;
764 $offset++;
768 $is_first_match = 0;
770 return;
777 my $match_column_number;
779 # does_match() MUST have an $opt->{regex} set.
781 sub does_match {
782 my ( $opt, $line ) = @_;
784 $match_column_number = undef;
786 if ( $opt->{v} ) {
787 return ( $line !~ /$opt->{regex}/o );
789 else {
790 if ( $line =~ /$opt->{regex}/o ) {
791 # @- = @LAST_MATCH_START
792 # @+ = @LAST_MATCH_END
793 $match_column_number = $-[0] + 1;
794 return 1;
796 else {
797 return;
802 sub get_match_column {
803 return $match_column_number;
808 sub resource_has_match {
809 my ( $resource, $opt ) = @_;
811 my $has_match = 0;
812 my $fh = $resource->open();
813 if ( !$fh ) {
814 if ( $App::Ack::report_bad_filenames ) {
815 App::Ack::warn( $resource->name . ': ' . $! );
818 else {
819 my $re = $opt->{regex};
820 if ( $opt->{v} ) {
821 while ( <$fh> ) {
822 if (!/$re/o) {
823 $has_match = 1;
824 last;
828 else {
829 # XXX read in chunks
830 # XXX only do this for certain file sizes?
831 my $content = do {
832 local $/;
833 <$fh>;
835 $has_match = $content =~ /$re/og;
837 close $fh;
840 return $has_match;
843 sub count_matches_in_resource {
844 my ( $resource, $opt ) = @_;
846 my $nmatches = 0;
847 my $fh = $resource->open();
848 if ( !$fh ) {
849 if ( $App::Ack::report_bad_filenames ) {
850 App::Ack::warn( $resource->name . ': ' . $! );
853 else {
854 my $re = $opt->{regex};
855 if ( $opt->{v} ) {
856 while ( <$fh> ) {
857 ++$nmatches if (!/$re/o);
860 else {
861 my $content = do {
862 local $/;
863 <$fh>;
865 $nmatches =()= ($content =~ /$re/og);
867 close $fh;
870 return $nmatches;
873 sub main {
874 my @arg_sources = App::Ack::ConfigLoader::retrieve_arg_sources();
876 my $opt = App::Ack::ConfigLoader::process_args( @arg_sources );
878 $App::Ack::report_bad_filenames = !$opt->{dont_report_bad_filenames};
880 if ( $opt->{flush} ) {
881 $| = 1;
884 if ( !defined($opt->{color}) && !$opt->{g} ) {
885 my $windows_color = 1;
886 if ( $App::Ack::is_windows ) {
887 $windows_color = eval { require Win32::Console::ANSI; };
889 $opt->{color} = !App::Ack::output_to_pipe() && $windows_color;
891 if ( not defined $opt->{heading} and not defined $opt->{break} ) {
892 $opt->{heading} = $opt->{break} = !App::Ack::output_to_pipe();
895 if ( defined($opt->{H}) || defined($opt->{h}) ) {
896 $opt->{show_filename}= $opt->{H} && !$opt->{h};
899 if ( my $output = $opt->{output} ) {
900 $output =~ s{\\}{\\\\}g;
901 $output =~ s{"}{\\"}g;
902 $opt->{output} = qq{"$output"};
905 my $resources;
906 if ( $App::Ack::is_filter_mode && !$opt->{files_from} ) { # probably -x
907 $resources = App::Ack::Resources->from_stdin( $opt );
908 my $regex = $opt->{regex};
909 $regex = shift @ARGV if not defined $regex;
910 $opt->{regex} = build_regex( $regex, $opt );
912 else {
913 if ( $opt->{f} || $opt->{lines} ) {
914 if ( $opt->{regex} ) {
915 App::Ack::warn( "regex ($opt->{regex}) specified with -f or --lines" );
916 App::Ack::exit_from_ack( 0 ); # XXX the 0 is misleading
919 else {
920 my $regex = $opt->{regex};
921 $regex = shift @ARGV if not defined $regex;
922 $opt->{regex} = build_regex( $regex, $opt );
924 my @start;
925 if ( not defined $opt->{files_from} ) {
926 @start = @ARGV;
928 if ( !exists($opt->{show_filename}) ) {
929 unless(@start == 1 && !(-d $start[0])) {
930 $opt->{show_filename} = 1;
934 if ( defined $opt->{files_from} ) {
935 $resources = App::Ack::Resources->from_file( $opt, $opt->{files_from} );
936 exit 1 unless $resources;
938 else {
939 @start = ('.') unless @start;
940 foreach my $target (@start) {
941 if ( !-e $target && $App::Ack::report_bad_filenames) {
942 App::Ack::warn( "$target: No such file or directory" );
946 $opt->{file_filter} = _compile_file_filter($opt, \@start);
947 $opt->{descend_filter} = _compile_descend_filter($opt);
949 $resources = App::Ack::Resources->from_argv( $opt, \@start );
952 App::Ack::set_up_pager( $opt->{pager} ) if defined $opt->{pager};
954 my $print_filenames = $opt->{show_filename};
955 my $max_count = $opt->{m};
956 my $ors = $opt->{print0} ? "\0" : "\n";
957 my $only_first = $opt->{1};
959 my $nmatches = 0;
960 my $total_count = 0;
961 RESOURCES:
962 while ( my $resource = $resources->next ) {
963 # XXX Combine the -f and -g functions
964 if ( $opt->{f} ) {
965 # XXX printing should probably happen inside of App::Ack
966 if ( $opt->{show_types} ) {
967 show_types( $resource, $ors );
969 else {
970 App::Ack::print( $resource->name, $ors );
972 ++$nmatches;
973 last RESOURCES if defined($max_count) && $nmatches >= $max_count;
975 elsif ( $opt->{g} ) {
976 if ( $opt->{show_types} ) {
977 show_types( $resource, $ors );
979 else {
980 local $opt->{show_filename} = 0; # XXX Why is this local?
982 print_line_with_options($opt, '', $resource->name, 0, $ors);
984 ++$nmatches;
985 last RESOURCES if defined($max_count) && $nmatches >= $max_count;
987 elsif ( $opt->{lines} ) {
988 my $print_filename = $opt->{show_filename};
989 my $passthru = $opt->{passthru};
991 my %line_numbers;
992 foreach my $line ( @{ $opt->{lines} } ) {
993 my @lines = split /,/, $line;
994 @lines = map {
995 /^(\d+)-(\d+)$/
996 ? ( $1 .. $2 )
997 : $_
998 } @lines;
999 @line_numbers{@lines} = (1) x @lines;
1002 my $filename = $resource->name;
1004 local $opt->{color} = 0;
1006 iterate($resource, $opt, sub {
1007 chomp;
1009 if ( $line_numbers{$.} ) {
1010 print_line_with_context($opt, $filename, $_, $.);
1012 elsif ( $passthru ) {
1013 print_line_with_options($opt, $filename, $_, $., ':');
1015 return 1;
1018 elsif ( $opt->{count} ) {
1019 my $matches_for_this_file = count_matches_in_resource( $resource, $opt );
1021 if ( not $opt->{show_filename} ) {
1022 $total_count += $matches_for_this_file;
1023 next RESOURCES;
1026 if ( !$opt->{l} || $matches_for_this_file > 0) {
1027 if ( $print_filenames ) {
1028 App::Ack::print( $resource->name, ':', $matches_for_this_file, $ors );
1030 else {
1031 App::Ack::print( $matches_for_this_file, $ors );
1035 elsif ( $opt->{l} || $opt->{L} ) {
1036 my $is_match = resource_has_match( $resource, $opt );
1038 if ( $opt->{L} ? !$is_match : $is_match ) {
1039 App::Ack::print( $resource->name, $ors );
1040 ++$nmatches;
1042 last RESOURCES if $only_first;
1043 last RESOURCES if defined($max_count) && $nmatches >= $max_count;
1046 else {
1047 $nmatches += print_matches_in_resource( $resource, $opt );
1048 if ( $nmatches && $only_first ) {
1049 last RESOURCES;
1054 if ( $opt->{count} && !$opt->{show_filename} ) {
1055 App::Ack::print( $total_count, "\n" );
1058 close $App::Ack::fh;
1059 App::Ack::exit_from_ack( $nmatches );
1064 =head1 NAME
1066 ack - grep-like text finder
1068 =head1 SYNOPSIS
1070 ack [options] PATTERN [FILE...]
1071 ack -f [options] [DIRECTORY...]
1073 =head1 DESCRIPTION
1075 Ack is designed as an alternative to F<grep> for programmers.
1077 Ack searches the named input FILEs (or standard input if no files
1078 are named, or the file name - is given) for lines containing a match
1079 to the given PATTERN. By default, ack prints the matching lines.
1081 PATTERN is a Perl regular expression. Perl regular expressions
1082 are commonly found in other programming languages, but for the particulars
1083 of their behavior, please consult
1084 L<http://perldoc.perl.org/perlreref.html|perlreref>. If you don't know
1085 how to use regular expression but are interested in learning, you may
1086 consult L<http://perldoc.perl.org/perlretut.html|perlretut>. If you do not
1087 need or want ack to use regular expressions, please see the
1088 C<-Q>/C<--literal> option.
1090 Ack can also list files that would be searched, without actually
1091 searching them, to let you take advantage of ack's file-type filtering
1092 capabilities.
1094 =head1 FILE SELECTION
1096 If files are not specified for searching, either on the command
1097 line or piped in with the C<-x> option, I<ack> delves into
1098 subdirectories selecting files for searching.
1100 I<ack> is intelligent about the files it searches. It knows about
1101 certain file types, based on both the extension on the file and,
1102 in some cases, the contents of the file. These selections can be
1103 made with the B<--type> option.
1105 With no file selection, I<ack> searches through regular files that
1106 are not explicitly excluded by B<--ignore-dir> and B<--ignore-file>
1107 options, either present in F<ackrc> files or on the command line.
1109 The default options for I<ack> ignore certain files and directories. These
1110 include:
1112 =over 4
1114 =item * Backup files: Files matching F<#*#> or ending with F<~>.
1116 =item * Coredumps: Files matching F<core.\d+>
1118 =item * Version control directories like F<.svn> and F<.git>.
1120 =back
1122 Run I<ack> with the C<--dump> option to see what settings are set.
1124 However, I<ack> always searches the files given on the command line,
1125 no matter what type. If you tell I<ack> to search in a coredump,
1126 it will search in a coredump.
1128 =head1 DIRECTORY SELECTION
1130 I<ack> descends through the directory tree of the starting directories
1131 specified. If no directories are specified, the current working directory is
1132 used. However, it will ignore the shadow directories used by
1133 many version control systems, and the build directories used by the
1134 Perl MakeMaker system. You may add or remove a directory from this
1135 list with the B<--[no]ignore-dir> option. The option may be repeated
1136 to add/remove multiple directories from the ignore list.
1138 For a complete list of directories that do not get searched, run
1139 C<ack --dump>.
1141 =head1 WHEN TO USE GREP
1143 I<ack> trumps I<grep> as an everyday tool 99% of the time, but don't
1144 throw I<grep> away, because there are times you'll still need it.
1146 E.g., searching through huge files looking for regexes that can be
1147 expressed with I<grep> syntax should be quicker with I<grep>.
1149 If your script or parent program uses I<grep> C<--quiet> or C<--silent>
1150 or needs exit 2 on IO error, use I<grep>.
1152 =head1 OPTIONS
1154 =over 4
1156 =item B<--ackrc>
1158 Specifies an ackrc file to load after all others; see L</"ACKRC LOCATION SEMANTICS">.
1160 =item B<-A I<NUM>>, B<--after-context=I<NUM>>
1162 Print I<NUM> lines of trailing context after matching lines.
1164 =item B<-B I<NUM>>, B<--before-context=I<NUM>>
1166 Print I<NUM> lines of leading context before matching lines.
1168 =item B<--[no]break>
1170 Print a break between results from different files. On by default
1171 when used interactively.
1173 =item B<-C [I<NUM>]>, B<--context[=I<NUM>]>
1175 Print I<NUM> lines (default 2) of context around matching lines.
1177 =item B<-c>, B<--count>
1179 Suppress normal output; instead print a count of matching lines for
1180 each input file. If B<-l> is in effect, it will only show the
1181 number of lines for each file that has lines matching. Without
1182 B<-l>, some line counts may be zeroes.
1184 If combined with B<-h> (B<--no-filename>) ack outputs only one total
1185 count.
1187 =item B<--[no]color>, B<--[no]colour>
1189 B<--color> highlights the matching text. B<--nocolor> suppresses
1190 the color. This is on by default unless the output is redirected.
1192 On Windows, this option is off by default unless the
1193 L<Win32::Console::ANSI> module is installed or the C<ACK_PAGER_COLOR>
1194 environment variable is used.
1196 =item B<--color-filename=I<color>>
1198 Sets the color to be used for filenames.
1200 =item B<--color-match=I<color>>
1202 Sets the color to be used for matches.
1204 =item B<--color-lineno=I<color>>
1206 Sets the color to be used for line numbers.
1208 =item B<--[no]column>
1210 Show the column number of the first match. This is helpful for
1211 editors that can place your cursor at a given position.
1213 =item B<--create-ackrc>
1215 Dumps the default ack options to standard output. This is useful for
1216 when you want to customize the defaults.
1218 =item B<--dump>
1220 Writes the list of options loaded and where they came from to standard
1221 output. Handy for debugging.
1223 =item B<--[no]env>
1225 B<--noenv> disables all environment processing. No F<.ackrc> is
1226 read and all environment variables are ignored. By default, F<ack>
1227 considers F<.ackrc> and settings in the environment.
1229 =item B<--flush>
1231 B<--flush> flushes output immediately. This is off by default
1232 unless ack is running interactively (when output goes to a pipe or
1233 file).
1235 =item B<-f>
1237 Only print the files that would be searched, without actually doing
1238 any searching. PATTERN must not be specified, or it will be taken
1239 as a path to search.
1241 =item B<--files-from=I<FILE>>
1243 The list of files to be searched is specified in I<FILE>. The list of
1244 files are separated by newlines. If I<FILE> is C<->, the list is loaded
1245 from standard input.
1247 =item B<--[no]filter>
1249 Forces ack to act as if it were receiving input via a pipe.
1251 =item B<--[no]follow>
1253 Follow or don't follow symlinks, other than whatever starting files
1254 or directories were specified on the command line.
1256 This is off by default.
1258 =item B<-g I<PATTERN>>
1260 Print files where the relative path + filename matches I<PATTERN>.
1261 This option can be combined with B<--color> to make it easier to spot
1262 the match.
1264 =item B<--[no]group>
1266 B<--group> groups matches by file name. This is the default
1267 when used interactively.
1269 B<--nogroup> prints one result per line, like grep. This is the
1270 default when output is redirected.
1272 =item B<-H>, B<--with-filename>
1274 Print the filename for each match. This is the default unless searching
1275 a single explicitly specified file.
1277 =item B<-h>, B<--no-filename>
1279 Suppress the prefixing of filenames on output when multiple files are
1280 searched.
1282 =item B<--[no]heading>
1284 Print a filename heading above each file's results. This is the default
1285 when used interactively.
1287 =item B<--help>, B<-?>
1289 Print a short help statement.
1291 =item B<--help-types>, B<--help=types>
1293 Print all known types.
1295 =item B<-i>, B<--ignore-case>
1297 Ignore case distinctions in PATTERN
1299 =item B<--ignore-ack-defaults>
1301 Tells ack to completely ignore the default definitions provided with ack.
1302 This is useful in combination with B<--create-ackrc> if you I<really> want
1303 to customize ack.
1305 =item B<--[no]ignore-dir=I<DIRNAME>>, B<--[no]ignore-directory=I<DIRNAME>>
1307 Ignore directory (as CVS, .svn, etc are ignored). May be used
1308 multiple times to ignore multiple directories. For example, mason
1309 users may wish to include B<--ignore-dir=data>. The B<--noignore-dir>
1310 option allows users to search directories which would normally be
1311 ignored (perhaps to research the contents of F<.svn/props> directories).
1313 The I<DIRNAME> must always be a simple directory name. Nested
1314 directories like F<foo/bar> are NOT supported. You would need to
1315 specify B<--ignore-dir=foo> and then no files from any foo directory
1316 are taken into account by ack unless given explicitly on the command
1317 line.
1319 =item B<--ignore-file=I<FILTERTYPE:FILTERARGS>>
1321 Ignore files matching I<FILTERTYPE:FILTERARGS>. The filters are specified
1322 identically to file type filters as seen in L</"Defining your own types">.
1324 =item B<-k>, B<--known-types>
1326 Limit selected files to those with types that ack knows about. This is
1327 equivalent to the default behavior found in ack 1.
1329 =item B<--lines=I<NUM>>
1331 Only print line I<NUM> of each file. Multiple lines can be given with multiple
1332 B<--lines> options or as a comma separated list (B<--lines=3,5,7>). B<--lines=4-7>
1333 also works. The lines are always output in ascending order, no matter the
1334 order given on the command line.
1336 =item B<-l>, B<--files-with-matches>
1338 Only print the filenames of matching files, instead of the matching text.
1340 =item B<-L>, B<--files-without-matches>
1342 Only print the filenames of files that do I<NOT> match.
1344 =item B<--match I<PATTERN>>
1346 Specify the I<PATTERN> explicitly. This is helpful if you don't want to put the
1347 regex as your first argument, e.g. when executing multiple searches over the
1348 same set of files.
1350 # search for foo and bar in given files
1351 ack file1 t/file* --match foo
1352 ack file1 t/file* --match bar
1354 =item B<-m=I<NUM>>, B<--max-count=I<NUM>>
1356 Stop reading a file after I<NUM> matches.
1358 =item B<--man>
1360 Print this manual page.
1362 =item B<-n>, B<--no-recurse>
1364 No descending into subdirectories.
1366 =item B<-o>
1368 Show only the part of each line matching PATTERN (turns off text
1369 highlighting)
1371 =item B<--output=I<expr>>
1373 Output the evaluation of I<expr> for each line (turns off text
1374 highlighting)
1375 If PATTERN matches more than once then a line is output for each non-overlapping match.
1376 For more information please see the section L</"Examples of F<--output>">.
1378 =item B<--pager=I<program>>, B<--nopager>
1380 B<--pager> directs ack's output through I<program>. This can also be specified
1381 via the C<ACK_PAGER> and C<ACK_PAGER_COLOR> environment variables.
1383 Using --pager does not suppress grouping and coloring like piping
1384 output on the command-line does.
1386 B<--nopager> cancels any setting in ~/.ackrc, C<ACK_PAGER> or C<ACK_PAGER_COLOR>.
1387 No output will be sent through a pager.
1389 =item B<--passthru>
1391 Prints all lines, whether or not they match the expression. Highlighting
1392 will still work, though, so it can be used to highlight matches while
1393 still seeing the entire file, as in:
1395 # Watch a log file, and highlight a certain IP address
1396 $ tail -f ~/access.log | ack --passthru 123.45.67.89
1398 =item B<--print0>
1400 Only works in conjunction with -f, -g, -l or -c (filename output). The filenames
1401 are output separated with a null byte instead of the usual newline. This is
1402 helpful when dealing with filenames that contain whitespace, e.g.
1404 # remove all files of type html
1405 ack -f --html --print0 | xargs -0 rm -f
1407 =item B<-Q>, B<--literal>
1409 Quote all metacharacters in PATTERN, it is treated as a literal.
1411 =item B<-r>, B<-R>, B<--recurse>
1413 Recurse into sub-directories. This is the default and just here for
1414 compatibility with grep. You can also use it for turning B<--no-recurse> off.
1416 =item B<-s>
1418 Suppress error messages about nonexistent or unreadable files. This is taken
1419 from fgrep.
1421 =item B<--[no]smart-case>, B<--no-smart-case>
1423 Ignore case in the search strings if PATTERN contains no uppercase
1424 characters. This is similar to C<smartcase> in vim. This option is
1425 off by default, and ignored if C<-i> is specified.
1427 B<-i> always overrides this option.
1429 =item B<--sort-files>
1431 Sorts the found files lexicographically. Use this if you want your file
1432 listings to be deterministic between runs of I<ack>.
1434 =item B<--show-types>
1436 Outputs the filetypes that ack associates with each file.
1438 Works with B<-f> and B<-g> options.
1440 =item B<--type=[no]TYPE>
1442 Specify the types of files to include or exclude from a search.
1443 TYPE is a filetype, like I<perl> or I<xml>. B<--type=perl> can
1444 also be specified as B<--perl>, and B<--type=noperl> can be done
1445 as B<--noperl>.
1447 If a file is of both type "foo" and "bar", specifying --foo and
1448 --nobar will exclude the file, because an exclusion takes precedence
1449 over an inclusion.
1451 Type specifications can be repeated and are ORed together.
1453 See I<ack --help=types> for a list of valid types.
1455 =item B<--type-add I<TYPE>:I<FILTER>:I<FILTERARGS>>
1457 Files with the given FILTERARGS applied to the given FILTER
1458 are recognized as being of (the existing) type TYPE.
1459 See also L</"Defining your own types">.
1462 =item B<--type-set I<TYPE>:I<FILTER>:I<FILTERARGS>>
1464 Files with the given FILTERARGS applied to the given FILTER are recognized as
1465 being of type TYPE. This replaces an existing definition for type TYPE. See
1466 also L</"Defining your own types">.
1468 =item B<--type-del I<TYPE>>
1470 The filters associated with TYPE are removed from Ack, and are no longer considered
1471 for searches.
1473 =item B<-v>, B<--invert-match>
1475 Invert match: select non-matching lines
1477 =item B<--version>
1479 Display version and copyright information.
1481 =item B<-w>, B<--word-regexp>
1483 Force PATTERN to match only whole words. The PATTERN is wrapped with
1484 C<\b> metacharacters.
1486 =item B<-x>
1488 An abbreviation for B<--files-from=->; the list of files to search are read
1489 from standard input, with one line per file.
1491 =item B<-1>
1493 Stops after reporting first match of any kind. This is different
1494 from B<--max-count=1> or B<-m1>, where only one match per file is
1495 shown. Also, B<-1> works with B<-f> and B<-g>, where B<-m> does
1496 not.
1498 =item B<--thpppt>
1500 Display the all-important Bill The Cat logo. Note that the exact
1501 spelling of B<--thpppppt> is not important. It's checked against
1502 a regular expression.
1504 =item B<--bar>
1506 Check with the admiral for traps.
1508 =item B<--cathy>
1510 Chocolate, Chocolate, Chocolate!
1512 =back
1514 =head1 THE .ackrc FILE
1516 The F<.ackrc> file contains command-line options that are prepended
1517 to the command line before processing. Multiple options may live
1518 on multiple lines. Lines beginning with a # are ignored. A F<.ackrc>
1519 might look like this:
1521 # Always sort the files
1522 --sort-files
1524 # Always color, even if piping to a another program
1525 --color
1527 # Use "less -r" as my pager
1528 --pager=less -r
1530 Note that arguments with spaces in them do not need to be quoted,
1531 as they are not interpreted by the shell. Basically, each I<line>
1532 in the F<.ackrc> file is interpreted as one element of C<@ARGV>.
1534 F<ack> looks in several locations for F<.ackrc> files; the searching
1535 process is detailed in L</"ACKRC LOCATION SEMANTICS">. These
1536 files are not considered if B<--noenv> is specified on the command line.
1538 =head1 Defining your own types
1540 ack allows you to define your own types in addition to the predefined
1541 types. This is done with command line options that are best put into
1542 an F<.ackrc> file - then you do not have to define your types over and
1543 over again. In the following examples the options will always be shown
1544 on one command line so that they can be easily copy & pasted.
1546 I<ack --perl foo> searches for foo in all perl files. I<ack --help=types>
1547 tells you, that perl files are files ending
1548 in .pl, .pm, .pod or .t. So what if you would like to include .xs
1549 files as well when searching for --perl files? I<ack --type-add perl:ext:xs --perl foo>
1550 does this for you. B<--type-add> appends
1551 additional extensions to an existing type.
1553 If you want to define a new type, or completely redefine an existing
1554 type, then use B<--type-set>. I<ack --type-set eiffel:ext:e,eiffel> defines
1555 the type I<eiffel> to include files with
1556 the extensions .e or .eiffel. So to search for all eiffel files
1557 containing the word Bertrand use I<ack --type-set eiffel:ext:e,eiffel --eiffel Bertrand>.
1558 As usual, you can also write B<--type=eiffel>
1559 instead of B<--eiffel>. Negation also works, so B<--noeiffel> excludes
1560 all eiffel files from a search. Redefining also works: I<ack --type-set cc:ext:c,h>
1561 and I<.xs> files no longer belong to the type I<cc>.
1563 When defining your own types in the F<.ackrc> file you have to use
1564 the following:
1566 --type-set=eiffel:ext:e,eiffel
1568 or writing on separate lines
1570 --type-set
1571 eiffel:ext:e,eiffel
1573 The following does B<NOT> work in the F<.ackrc> file:
1575 --type-set eiffel:ext:e,eiffel
1578 In order to see all currently defined types, use I<--help-types>, e.g.
1579 I<ack --type-set backup:ext:bak --type-add perl:ext:perl --help-types>
1581 In addition to filtering based on extension (like ack 1.x allowed), ack 2
1582 offers additional filter types. The generic syntax is
1583 I<--type-set TYPE:FILTER:FILTERARGS>; I<FILTERARGS> depends on the value
1584 of I<FILTER>.
1586 =over 4
1588 =item is:I<FILENAME>
1590 I<is> filters match the target filename exactly. It takes exactly one
1591 argument, which is the name of the file to match.
1593 Example:
1595 --type-set make:is:Makefile
1597 =item ext:I<EXTENSION>[,I<EXTENSION2>[,...]]
1599 I<ext> filters match the extension of the target file against a list
1600 of extensions. No leading dot is needed for the extensions.
1602 Example:
1604 --type-set perl:ext:pl,pm,t
1606 =item match:I<PATTERN>
1608 I<match> filters match the target filename against a regular expression.
1609 The regular expression is made case insensitive for the search.
1611 Example:
1613 --type-set make:match:/(gnu)?makefile/
1615 =item firstlinematch:I<PATTERN>
1617 I<firstlinematch> matches the first line of the target file against a
1618 regular expression. Like I<match>, the regular expression is made
1619 case insensitive.
1621 Example:
1623 --type-add perl:firstlinematch:/perl/
1625 =back
1627 More filter types may be made available in the future.
1629 =head1 ENVIRONMENT VARIABLES
1631 For commonly-used ack options, environment variables can make life
1632 much easier. These variables are ignored if B<--noenv> is specified
1633 on the command line.
1635 =over 4
1637 =item ACKRC
1639 Specifies the location of the user's F<.ackrc> file. If this file doesn't
1640 exist, F<ack> looks in the default location.
1642 =item ACK_OPTIONS
1644 This variable specifies default options to be placed in front of
1645 any explicit options on the command line.
1647 =item ACK_COLOR_FILENAME
1649 Specifies the color of the filename when it's printed in B<--group>
1650 mode. By default, it's "bold green".
1652 The recognized attributes are clear, reset, dark, bold, underline,
1653 underscore, blink, reverse, concealed black, red, green, yellow,
1654 blue, magenta, on_black, on_red, on_green, on_yellow, on_blue,
1655 on_magenta, on_cyan, and on_white. Case is not significant.
1656 Underline and underscore are equivalent, as are clear and reset.
1657 The color alone sets the foreground color, and on_color sets the
1658 background color.
1660 This option can also be set with B<--color-filename>.
1662 =item ACK_COLOR_MATCH
1664 Specifies the color of the matching text when printed in B<--color>
1665 mode. By default, it's "black on_yellow".
1667 This option can also be set with B<--color-match>.
1669 See B<ACK_COLOR_FILENAME> for the color specifications.
1671 =item ACK_COLOR_LINENO
1673 Specifies the color of the line number when printed in B<--color>
1674 mode. By default, it's "bold yellow".
1676 This option can also be set with B<--color-lineno>.
1678 See B<ACK_COLOR_FILENAME> for the color specifications.
1680 =item ACK_PAGER
1682 Specifies a pager program, such as C<more>, C<less> or C<most>, to which
1683 ack will send its output.
1685 Using C<ACK_PAGER> does not suppress grouping and coloring like
1686 piping output on the command-line does, except that on Windows
1687 ack will assume that C<ACK_PAGER> does not support color.
1689 C<ACK_PAGER_COLOR> overrides C<ACK_PAGER> if both are specified.
1691 =item ACK_PAGER_COLOR
1693 Specifies a pager program that understands ANSI color sequences.
1694 Using C<ACK_PAGER_COLOR> does not suppress grouping and coloring
1695 like piping output on the command-line does.
1697 If you are not on Windows, you never need to use C<ACK_PAGER_COLOR>.
1699 =back
1701 =head1 AVAILABLE COLORS
1703 F<ack> uses the colors available in Perl's L<Term::ANSIColor> module, which
1704 provides the following listed values. Note that case does not matter when using
1705 these values.
1707 =head2 Foreground colors
1709 black red green yellow blue magenta cyan white
1711 bright_black bright_red bright_green bright_yellow
1712 bright_blue bright_magenta bright_cyan bright_white
1714 =head2 Background colors
1716 on_black on_red on_green on_yellow
1717 on_blue on_magenta on_cyan on_white
1719 on_bright_black on_bright_red on_bright_green on_bright_yellow
1720 on_bright_blue on_bright_magenta on_bright_cyan on_bright_white
1722 =head1 ACK & OTHER TOOLS
1724 =head2 Vim integration
1726 F<ack> integrates easily with the Vim text editor. Set this in your
1727 F<.vimrc> to use F<ack> instead of F<grep>:
1729 set grepprg=ack\ -k
1731 That example uses C<-k> to search through only files of the types ack
1732 knows about, but you may use other default flags. Now you can search
1733 with F<ack> and easily step through the results in Vim:
1735 :grep Dumper perllib
1737 Miles Sterrett has written a Vim plugin for F<ack> which allows you to use
1738 C<:Ack> instead of C<:grep>, as well as several other advanced features.
1740 L<https://github.com/mileszs/ack.vim>
1742 =head2 Emacs integration
1744 Phil Jackson put together an F<ack.el> extension that "provides a
1745 simple compilation mode ... has the ability to guess what files you
1746 want to search for based on the major-mode."
1748 L<http://www.shellarchive.co.uk/content/emacs.html>
1750 =head2 TextMate integration
1752 Pedro Melo is a TextMate user who writes "I spend my day mostly
1753 inside TextMate, and the built-in find-in-project sucks with large
1754 projects. So I hacked a TextMate command that was using find +
1755 grep to use ack. The result is the Search in Project with ack, and
1756 you can find it here:
1757 L<http://www.simplicidade.org/notes/archives/2008/03/search_in_proje.html>"
1759 =head2 Shell and Return Code
1761 For greater compatibility with I<grep>, I<ack> in normal use returns
1762 shell return or exit code of 0 only if something is found and 1 if
1763 no match is found.
1765 (Shell exit code 1 is C<$?=256> in perl with C<system> or backticks.)
1767 The I<grep> code 2 for errors is not used.
1769 If C<-f> or C<-g> are specified, then 0 is returned if at least one
1770 file is found. If no files are found, then 1 is returned.
1772 =cut
1774 =head1 DEBUGGING ACK PROBLEMS
1776 If ack gives you output you're not expecting, start with a few simple steps.
1778 =head2 Use B<--noenv>
1780 Your environment variables and F<.ackrc> may be doing things you're
1781 not expecting, or forgotten you specified. Use B<--noenv> to ignore
1782 your environment and F<.ackrc>.
1784 =head2 Use B<-f> to see what files have been selected
1786 Ack's B<-f> was originally added as a debugging tool. If ack is
1787 not finding matches you think it should find, run F<ack -f> to see
1788 what files have been selected. You can also add the C<--show-types>
1789 options to show the type of each file selected.
1791 =head2 Use B<--dump>
1793 This lists the ackrc files that are loaded and the options loaded
1794 from them.
1795 So for example you can find a list of directories that do not get searched or where filetypes are defined.
1797 =head1 TIPS
1799 =head2 Use the F<.ackrc> file.
1801 The F<.ackrc> is the place to put all your options you use most of
1802 the time but don't want to remember. Put all your --type-add and
1803 --type-set definitions in it. If you like --smart-case, set it
1804 there, too. I also set --sort-files there.
1806 =head2 Use F<-f> for working with big codesets
1808 Ack does more than search files. C<ack -f --perl> will create a
1809 list of all the Perl files in a tree, ideal for sending into F<xargs>.
1810 For example:
1812 # Change all "this" to "that" in all Perl files in a tree.
1813 ack -f --perl | xargs perl -p -i -e's/this/that/g'
1815 or if you prefer:
1817 perl -p -i -e's/this/that/g' $(ack -f --perl)
1819 =head2 Use F<-Q> when in doubt about metacharacters
1821 If you're searching for something with a regular expression
1822 metacharacter, most often a period in a filename or IP address, add
1823 the -Q to avoid false positives without all the backslashing. See
1824 the following example for more...
1826 =head2 Use ack to watch log files
1828 Here's one I used the other day to find trouble spots for a website
1829 visitor. The user had a problem loading F<troublesome.gif>, so I
1830 took the access log and scanned it with ack twice.
1832 ack -Q aa.bb.cc.dd /path/to/access.log | ack -Q -B5 troublesome.gif
1834 The first ack finds only the lines in the Apache log for the given
1835 IP. The second finds the match on my troublesome GIF, and shows
1836 the previous five lines from the log in each case.
1838 =head2 Examples of F<--output>
1840 Following variables are useful in the expansion string:
1842 =over 4
1844 =item C<$&>
1846 The whole string matched by PATTERN.
1848 =item C<$1>, C<$2>, ...
1850 The contents of the 1st, 2nd ... bracketed group in PATTERN.
1852 =item C<$`>
1854 The string before the match.
1856 =item C<$'>
1858 The string after the match.
1860 =back
1862 For more details and other variables see
1863 L<http://perldoc.perl.org/perlvar.html#Variables-related-to-regular-expressions|perlvar>.
1865 This example shows how to add text around a particular pattern
1866 (in this case adding _ around word with "e")
1868 ack2.pl "\w*e\w*" quick.txt --output="$`_$&_$'"
1869 _The_ quick brown fox jumps over the lazy dog
1870 The quick brown fox jumps _over_ the lazy dog
1871 The quick brown fox jumps over _the_ lazy dog
1873 This shows how to pick out particular parts of a match using ( ) within regular expression.
1875 ack '=head(\d+)\s+(.*)' --output=' $1 : $2'
1876 input file contains "=head1 NAME"
1877 output "1 : NAME"
1879 =head2 Share your knowledge
1881 Join the ack-users mailing list. Send me your tips and I may add
1882 them here.
1884 =head1 FAQ
1886 =head2 Why isn't ack finding a match in (some file)?
1888 Probably because it's of a type that ack doesn't recognize. ack's
1889 searching behavior is driven by filetype. B<If ack doesn't know
1890 what kind of file it is, ack ignores the file.>
1892 Use the C<-f> switch to see a list of files that ack will search
1893 for you. You can use the C<--show-types> switch to show which type
1894 ack thinks each file is.
1896 =head2 Wouldn't it be great if F<ack> did search & replace?
1898 No, ack will always be read-only. Perl has a perfectly good way
1899 to do search & replace in files, using the C<-i>, C<-p> and C<-n>
1900 switches.
1902 You can certainly use ack to select your files to update. For
1903 example, to change all "foo" to "bar" in all PHP files, you can do
1904 this from the Unix shell:
1906 $ perl -i -p -e's/foo/bar/g' $(ack -f --php)
1908 =head2 Can I make ack recognize F<.xyz> files?
1910 Yes! Please see L</"Defining your own types">. If you think
1911 that F<ack> should recognize a type by default, please see
1912 L</"ENHANCEMENTS">.
1914 =head2 There's already a program/package called ack.
1916 Yes, I know.
1918 =head2 Why is it called ack if it's called ack-grep?
1920 The name of the program is "ack". Some packagers have called it
1921 "ack-grep" when creating packages because there's already a package
1922 out there called "ack" that has nothing to do with this ack.
1924 I suggest you make a symlink named F<ack> that points to F<ack-grep>
1925 because one of the crucial benefits of ack is having a name that's
1926 so short and simple to type.
1928 To do that, run this with F<sudo> or as root:
1930 ln -s /usr/bin/ack-grep /usr/bin/ack
1932 Alternatively, you could use a shell alias:
1934 # bash/zsh
1935 alias ack=ack-grep
1937 # csh
1938 alias ack ack-grep
1940 =head2 What does F<ack> mean?
1942 Nothing. I wanted a name that was easy to type and that you could
1943 pronounce as a single syllable.
1945 =head2 Can I do multi-line regexes?
1947 No, ack does not support regexes that match multiple lines. Doing
1948 so would require reading in the entire file at a time.
1950 If you want to see lines near your match, use the C<--A>, C<--B>
1951 and C<--C> switches for displaying context.
1953 =head2 Why is ack telling me I have an invalid option when searching for C<+foo>?
1955 ack treats command line options beginning with C<+> or C<-> as options; if you
1956 would like to search for these, you may prefix your search term with C<--> or
1957 use the C<--match> option. (However, don't forget that C<+> is a regular
1958 expression metacharacter!)
1960 =head2 Why does C<"ack '.{40000,}'"> fail? Isn't that a valid regex?
1962 The Perl language limits the repetition quanitifier to 32K. You
1963 can search for C<.{32767}> but not C<.{32768}>.
1965 =head1 ACKRC LOCATION SEMANTICS
1967 Ack can load its configuration from many sources. This list
1968 specifies the sources Ack looks for configuration; each one
1969 that is found is loaded in the order specified here, and
1970 each one overrides options set in any of the sources preceding
1971 it. (For example, if I set --sort-files in my user ackrc, and
1972 --nosort-files on the command line, the command line takes
1973 precedence)
1975 =over 4
1977 =item *
1979 Defaults are loaded from App::Ack::ConfigDefaults. This can be omitted
1980 using C<--ignore-ack-defaults>.
1982 =item * Global ackrc
1984 Options are then loaded from the global ackrc. This is located at
1985 C</etc/ackrc> on Unix-like systems.
1987 Under Windows XP and earlier, the ackrc is at
1988 C<C:\Documents and Settings\All Users\Application Data\ackrc>.
1990 Under Windows Vista/7, the global ackrc is at
1991 C<C:\ProgramData>
1993 The C<--noenv> option prevents all ackrc files from being loaded.
1995 =item * User ackrc
1997 Options are then loaded from the user's ackrc. This is located at
1998 C<$HOME/.ackrc> on Unix-like systems.
2000 Under Windows XP and earlier, the user's ackrc is at
2001 C<C:\Documents and Settings\$USER\Application Data\ackrc>.
2003 Under Windows Vista/7, the user's ackrc is at
2004 <C:\Users\$USER\AppData\Roaming>.
2006 If you want to load a different user-level ackrc, it may be specified
2007 with the C<$ACKRC> environment variable.
2009 The C<--noenv> option prevents all ackrc files from being loaded.
2011 =item * Project ackrc
2013 Options are then loaded from the project ackrc. The project ackrc is
2014 the first ackrc file with the name C<.ackrc> or C<_ackrc>, first searching
2015 in the current directory, then the parent directory, then the grandparent
2016 directory, etc. This can be omitted using C<--noenv>.
2018 =item * --ackrc
2020 The C<--ackrc> option may be included on the command line to specify an
2021 ackrc file that can override all others. It is consulted even if C<--noenv>
2022 is present.
2024 =item * ACK_OPTIONS
2026 Options are then loaded from the environment variable C<ACK_OPTIONS>. This can
2027 be omitted using C<--noenv>.
2029 =item * Command line
2031 Options are then loaded from the command line.
2033 =back
2035 =head1 DIFFERENCES BETWEEN ACK 1.X AND ACK 2.X
2037 A lot of changes were made for ack 2; here is a list of them.
2039 =head2 GENERAL CHANGES
2041 =over 4
2043 =item *
2045 When no selectors are specified, ack 1.x only searches through files that
2046 it can map to a file type. ack 2.x, by contrast, will search through
2047 every regular, non-binary file that is not explicitly ignored via
2048 B<--ignore-file> or B<--ignore-dir>. This is similar to the behavior of the
2049 B<-a/--all> option in ack 1.x.
2051 =item *
2053 A more flexible filter system has been added, so that more powerful file types
2054 may be created by the user. For details, please consult
2055 L</"Defining your own types">.
2057 =item *
2059 ack now loads multiple ackrc files; see L</"ACKRC LOCATION SEMANTICS"> for
2060 details.
2062 =item *
2064 ack's default filter definitions aren't special; you may tell ack to
2065 completely disregard them if you don't like them.
2067 =back
2069 =head2 REMOVED OPTIONS
2071 =over 4
2073 =item *
2075 Because of the change in default search behavior, the B<-a/--all> and
2076 B<-u/--unrestricted> options have been removed. In addition, the
2077 B<-k/--known-types> option was added to cause ack to behave with
2078 the default search behavior of ack 1.x.
2080 =item *
2082 The B<-G> option has been removed. Two regular expressions on the
2083 command line was considered too confusing; to simulate B<-G>'s functionality,
2084 you may use the new B<-x> option to pipe filenames from one invocation of
2085 ack into another.
2087 =item *
2089 The B<--binary> option has been removed.
2091 =item *
2093 The B<--skipped> option has been removed.
2095 =item *
2097 The B<--text> option has been removed.
2099 =item *
2101 The B<--invert-file-match> option has been removed. Instead, you may
2102 use B<-v> with B<-g>.
2104 =back
2106 =head2 CHANGED OPTIONS
2108 =over 4
2110 =item *
2112 The options that modify the regular expression's behavior (B<-i>, B<-w>,
2113 B<-Q>, and B<-v>) may now be used with B<-g>.
2115 =back
2117 =head2 ADDED OPTIONS
2119 =over 4
2121 =item *
2123 B<--files-from> was added so that a user may submit a list of filenames as
2124 a list of files to search.
2126 =item *
2128 B<-x> was added to tell ack to accept a list of filenames via standard input;
2129 this list is the list of filenames that will be used for the search.
2131 =item *
2133 B<-s> was added to tell ack to suppress error messages about non-existent or
2134 unreadable files.
2136 =item *
2138 B<--ignore-directory> and B<--noignore-directory> were added as aliases for
2139 B<--ignore-dir> and B<--noignore-dir> respectively.
2141 =item *
2143 B<--ignore-file> was added so that users may specify patterns of files to
2144 ignore (ex. /.*~$/).
2146 =item *
2148 B<--dump> was added to allow users to easily find out which options are
2149 set where.
2151 =item *
2153 B<--create-ackrc> was added so that users may create custom ackrc files based
2154 on the default settings loaded by ack, and so that users may easily view those
2155 defaults.
2157 =item *
2159 B<--type-del> was added to selectively remove file type definitions.
2161 =item *
2163 B<--ignore-ack-defaults> was added so that users may ignore ack's default
2164 options in favor of their own.
2166 =item *
2168 B<--bar> was added so ack users may consult Admiral Ackbar.
2170 =back
2172 =head1 AUTHOR
2174 Andy Lester, C<< <andy at petdance.com> >>
2176 =head1 BUGS
2178 Please report any bugs or feature requests to the issues list at
2179 Github: L<https://github.com/petdance/ack2/issues>
2181 =head1 ENHANCEMENTS
2183 All enhancement requests MUST first be posted to the ack-users
2184 mailing list at L<http://groups.google.com/group/ack-users>. I
2185 will not consider a request without it first getting seen by other
2186 ack users. This includes requests for new filetypes.
2188 There is a list of enhancements I want to make to F<ack> in the ack
2189 issues list at Github: L<https://github.com/petdance/ack2/issues>
2191 Patches are always welcome, but patches with tests get the most
2192 attention.
2194 =head1 SUPPORT
2196 Support for and information about F<ack> can be found at:
2198 =over 4
2200 =item * The ack homepage
2202 L<http://beyondgrep.com/>
2204 =item * The ack-users mailing list
2206 L<http://groups.google.com/group/ack-users>
2208 =item * The ack issues list at Github
2210 L<https://github.com/petdance/ack2/issues>
2212 =item * AnnoCPAN: Annotated CPAN documentation
2214 L<http://annocpan.org/dist/ack>
2216 =item * CPAN Ratings
2218 L<http://cpanratings.perl.org/d/ack>
2220 =item * Search CPAN
2222 L<http://search.cpan.org/dist/ack>
2224 =item * Git source repository
2226 L<https://github.com/petdance/ack2>
2228 =back
2230 =head1 ACKNOWLEDGEMENTS
2232 How appropriate to have I<ack>nowledgements!
2234 Thanks to everyone who has contributed to ack in any way, including
2235 Stephen Thirlwall,
2236 Jonah Bishop,
2237 Chris Rebert,
2238 Denis Howe,
2239 RaE<uacute>l GundE<iacute>n,
2240 James McCoy,
2241 Daniel Perrett,
2242 Steven Lee,
2243 Jonathan Perret,
2244 Fraser Tweedale,
2245 RaE<aacute>l GundE<aacute>n,
2246 Steffen Jaeckel,
2247 Stephan Hohe,
2248 Michael Beijen,
2249 Alexandr Ciornii,
2250 Christian Walde,
2251 Charles Lee,
2252 Joe McMahon,
2253 John Warwick,
2254 David Steinbrunner,
2255 Kara Martens,
2256 Volodymyr Medvid,
2257 Ron Savage,
2258 Konrad Borowski,
2259 Dale Sedivic,
2260 Michael McClimon,
2261 Andrew Black,
2262 Ralph Bodenner,
2263 Shaun Patterson,
2264 Ryan Olson,
2265 Shlomi Fish,
2266 Karen Etheridge,
2267 Olivier Mengue,
2268 Matthew Wild,
2269 Scott Kyle,
2270 Nick Hooey,
2271 Bo Borgerson,
2272 Mark Szymanski,
2273 Marq Schneider,
2274 Packy Anderson,
2275 JR Boyens,
2276 Dan Sully,
2277 Ryan Niebur,
2278 Kent Fredric,
2279 Mike Morearty,
2280 Ingmar Vanhassel,
2281 Eric Van Dewoestine,
2282 Sitaram Chamarty,
2283 Adam James,
2284 Richard Carlsson,
2285 Pedro Melo,
2286 AJ Schuster,
2287 Phil Jackson,
2288 Michael Schwern,
2289 Jan Dubois,
2290 Christopher J. Madsen,
2291 Matthew Wickline,
2292 David Dyck,
2293 Jason Porritt,
2294 Jjgod Jiang,
2295 Thomas Klausner,
2296 Uri Guttman,
2297 Peter Lewis,
2298 Kevin Riggle,
2299 Ori Avtalion,
2300 Torsten Blix,
2301 Nigel Metheringham,
2302 GE<aacute>bor SzabE<oacute>,
2303 Tod Hagan,
2304 Michael Hendricks,
2305 E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason,
2306 Piers Cawley,
2307 Stephen Steneker,
2308 Elias Lutfallah,
2309 Mark Leighton Fisher,
2310 Matt Diephouse,
2311 Christian Jaeger,
2312 Bill Sully,
2313 Bill Ricker,
2314 David Golden,
2315 Nilson Santos F. Jr,
2316 Elliot Shank,
2317 Merijn Broeren,
2318 Uwe Voelker,
2319 Rick Scott,
2320 Ask BjE<oslash>rn Hansen,
2321 Jerry Gay,
2322 Will Coleda,
2323 Mike O'Regan,
2324 Slaven ReziE<0x107>,
2325 Mark Stosberg,
2326 David Alan Pisoni,
2327 Adriano Ferreira,
2328 James Keenan,
2329 Leland Johnson,
2330 Ricardo Signes,
2331 Pete Krawczyk and
2332 Rob Hoelz.
2334 =head1 COPYRIGHT & LICENSE
2336 Copyright 2005-2014 Andy Lester.
2338 This program is free software; you can redistribute it and/or modify
2339 it under the terms of the Artistic License v2.0.
2341 See http://www.perlfoundation.org/artistic_license_2_0 or the LICENSE.md
2342 file that comes with the ack distribution.
2344 =cut
2345 package App::Ack;
2347 use warnings;
2348 use strict;
2351 our $VERSION;
2352 our $COPYRIGHT;
2353 BEGIN {
2354 $VERSION = '2.14';
2355 $COPYRIGHT = 'Copyright 2005-2014 Andy Lester.';
2358 our $fh;
2360 BEGIN {
2361 $fh = *STDOUT;
2365 our %types;
2366 our %type_wanted;
2367 our %mappings;
2368 our %ignore_dirs;
2370 our $is_filter_mode;
2371 our $output_to_pipe;
2373 our $dir_sep_chars;
2374 our $is_cygwin;
2375 our $is_windows;
2377 use File::Spec 1.00015 ();
2379 BEGIN {
2380 # These have to be checked before any filehandle diddling.
2381 $output_to_pipe = not -t *STDOUT;
2382 $is_filter_mode = -p STDIN;
2384 $is_cygwin = ($^O eq 'cygwin');
2385 $is_windows = ($^O eq 'MSWin32');
2386 $dir_sep_chars = $is_windows ? quotemeta( '\\/' ) : quotemeta( File::Spec->catfile( '', '' ) );
2391 sub remove_dir_sep {
2392 my $path = shift;
2393 $path =~ s/[$dir_sep_chars]$//;
2395 return $path;
2400 sub warn {
2401 return CORE::warn( _my_program(), ': ', @_, "\n" );
2405 sub die {
2406 return CORE::die( _my_program(), ': ', @_, "\n" );
2409 sub _my_program {
2410 require File::Basename;
2411 return File::Basename::basename( $0 );
2416 sub filetypes_supported {
2417 return keys %mappings;
2420 sub _get_thpppt {
2421 my $y = q{_ /|,\\'!.x',=(www)=, U };
2422 $y =~ tr/,x!w/\nOo_/;
2423 return $y;
2426 sub _thpppt {
2427 my $y = _get_thpppt();
2428 App::Ack::print( "$y ack $_[0]!\n" );
2429 exit 0;
2432 sub _bar {
2433 my $x;
2434 $x = <<'_BAR';
2435 6?!I'7!I"?%+!
2436 3~!I#7#I"7#I!?!+!="+"="+!:!
2437 2?#I!7!I!?#I!7!I"+"=%+"=#
2438 1?"+!?*+!=#~"=!+#?"="+!
2439 0?"+!?"I"?&+!="~!=!~"=!+%="+"
2440 /I!+!?)+!?!+!=$~!=!~!="+!="+"?!="?!
2441 .?%I"?%+%='?!=#~$="
2442 ,,!?%I"?(+$=$~!=#:"~$:!~!
2443 ,I!?!I!?"I"?!+#?"+!?!+#="~$:!~!:!~!:!,!:!,":#~!
2444 +I!?&+!="+!?#+$=!~":!~!:!~!:!,!:#,!:!,%:"
2445 *+!I!?!+$=!+!=!+!?$+#=!~":!~":#,$:",#:!,!:!
2446 *I!?"+!?!+!=$+!?#+#=#~":$,!:",!:!,&:"
2447 )I!?$=!~!=#+"?!+!=!+!=!~!="~!:!~":!,'.!,%:!~!
2448 (=!?"+!?!=!~$?"+!?!+!=#~"=",!="~$,$.",#.!:!=!
2449 (I"+"="~"=!+&=!~"=!~!,!~!+!=!?!+!?!=!I!?!+"=!.",!.!,":!
2450 %I$?!+!?!=%+!~!+#~!=!~#:#=!~!+!~!=#:!,%.!,!.!:"
2451 $I!?!=!?!I!+!?"+!=!~!=!~!?!I!?!=!+!=!~#:",!~"=!~!:"~!=!:",&:" '-/
2452 $?!+!I!?"+"=!+"~!,!:"+#~#:#,"=!~"=!,!~!,!.",!:".!:! */! !I!t!'!s! !a! !g!r!e!p!!! !/!
2453 $+"=!+!?!+"~!=!:!~!:"I!+!,!~!=!:!~!,!:!,$:!~".&:"~!,# (-/
2454 %~!=!~!=!:!.!+"~!:!,!.!,!~!=!:$.!,":!,!.!:!~!,!:!=!.#="~!,!:" ./!
2455 %=!~!?!+"?"+!=!~",!.!:!?!~!.!:!,!:!,#.!,!:","~!:!=!~!=!:",!~! ./!
2456 %+"~":!~!=#~!:!~!,!.!~!:",!~!=!~!.!:!,!.",!:!,":!=":!.!,!:!7! -/!
2457 %~",!:".#:!=!:!,!:"+!:!~!:!.!,!~!,!.#,!.!,$:"~!,":"~!=! */!
2458 &=!~!=#+!=!~",!.!:",#:#,!.",+:!,!.",!=!+!?!
2459 &~!=!~!=!~!:"~#:",!.!,#~!:!.!+!,!.",$.",$.#,!+!I!?!
2460 &~!="~!:!~":!~",!~!=!~":!,!:!~!,!:!,&.$,#."+!?!I!?!I!
2461 &~!=!~!=!+!,!:!~!:!=!,!:!~&:$,!.!,".!,".!,#."~!+!?$I!
2462 &~!=!~!="~!=!:!~":!,!~%:#,!:",!.!,#.",#I!7"I!?!+!?"I"
2463 &+!I!7!:#~"=!~!:!,!:"~$.!=!.!,!~!,$.#,!~!7!I#?!+!?"I"7!
2464 %7#?!+!~!:!=!~!=!~":!,!:"~":#.!,)7#I"?"I!7&
2465 %7#I!=":!=!~!:"~$:"~!:#,!:!,!:!~!:#,!7#I!?#7)
2466 $7$+!,!~!=#~!:!~!:!~$:#,!.!~!:!=!,":!7#I"?#7+=!?!
2467 $7#I!~!,!~#=!~!:"~!:!,!:!,#:!=!~",":!7$I!?#I!7*+!=!+"
2468 "I!7$I!,":!,!.!=":$,!:!,$:$7$I!+!?"I!7+?"I!7!I!7!,!
2469 !,!7%I!:",!."~":!,&.!,!:!~!I!7$I!+!?"I!7,?!I!7',!
2470 !7(,!.#~":!,%.!,!7%I!7!?#I"7,+!?!7*
2471 7+:!,!~#,"=!7'I!?#I"7/+!7+
2472 77I!+!7!?!7!I"71+!7,
2473 _BAR
2475 return App::Ack::__pic($x);
2478 sub _cathy {
2479 my $x = <<'CATHY';
2480 0+!--+!
2481 0|! "C!H!O!C!O!L!A!T!E!!! !|!
2482 0|! "C!H!O!C!O!L!A!T!E!!! !|!
2483 0|! "C!H!O!C!O!L!A!T!E!!! !|!
2484 0|! $A"C!K!!! $|!
2485 0+!--+!
2486 6\! 1:!,!.! !
2487 7\! /.!M!~!Z!M!~!
2488 8\! /~!D! "M! !
2489 4.! $\! /M!~!.!8! +.!M# 4
2490 0,!.! (\! .~!M!N! ,+!I!.!M!.! 3
2491 /?!O!.!M!:! '\! .O!.! +~!Z!=!N!.! 4
2492 ..! !D!Z!.!Z!.! '\! 9=!M".! 6
2493 /.! !.!~!M".! '\! 8~! 9
2494 4M!.! /.!7!N!M!.! F
2495 4.! &:!M! !N"M# !M"N!M! #D!M&=! =
2496 :M!7!M#:! !~!M!7!,!$!M!:! #.! !O!N!.!M!:!M# ;
2497 8Z!M"~!N!$!D!.!N!?! !I!N!.! (?!M! !M!,!D!M".! 9
2498 (?!Z!M!N!:! )=!M!O!8!.!M!+!M! !M!,! !O!M! +,!M!.!M!~!Z!N!M!:! &:!~! 0
2499 &8!7!.!~!M"D!M!,! &M!?!=!8! !M!,!O! !M!+! !+!O!.!M! $M#~! !.!8!M!Z!.!M! !O!M"Z! %:!~!M!Z!M!Z!.! +
2500 &:!M!7!,! *M!.!Z!M! !8"M!.!M!~! !.!M!.!=! #~!8!.!M! !7!M! "N!Z#I! !D!M!,!M!.! $."M!,! !M!.! *
2501 2$!O! "N! !.!M!I! !7" "M! "+!O! !~!M! !d!O!.!7!I!M!.! !.!O!=!M!.! !M",!M!.! %.!$!O!D! +
2502 1~!O! "M!+! !8!$! "M! "?!O! %Z!8!D!M!?!8!I!O!7!M! #M!.!M! "M",!M! 4
2503 07!~! ".!8! !.!M! "I!+! !.!M! &Z!D!.!7!=!M! !:!.!M! #:!8"+! !.!+!8! !8! 3
2504 /~!M! #N! !~!M!$! !.!M! !.!M" &~!M! "~!M!O! "D! $M! !8! "M!,!M!+!D!.! 1
2505 #.! #?!M!N!.! #~!O! $M!.!7!$! "?" !?!~!M! '7!8!?!M!.!+!M"O! $?"$!D! !.!O! !$!7!I!.! 0
2506 $,!M!:!O!?! ".! !?!=! $=!:!O! !M! "M! !M! !+!$! (.! +.!M! !M!.! !8! !+"Z!~! $:!M!$! !.! '
2507 #.!8!.!I!$! $7!I! %M" !=!M! !~!M!D! "7!I! .I!O! %?!=!,!D! !,!M! !D!~!8!~! %D!M! (
2508 #.!M"?! $=!O! %=!N! "8!.! !Z!M! #M!~! (M!:! #.!M" &O! !M!.! !?!,! !8!.!N!~! $8!N!M!,!.! %
2509 *$!O! &M!,! "O! !.!M!.! #M! (~!M( &O!.! !7! "M! !.!M!.!M!,! #.!M! !M! &
2510 )=!8!.! $.!M!O!.! "$!.!I!N! !I!M# (7!M(I! %D"Z!M! "=!I! "M! !M!:! #~!D! '
2511 )D! &8!N!:! ".!O! !M!="M! "M! (7!M) %." !M!D!."M!.! !$!=! !M!,! +
2512 (M! &+!.!M! #Z!7!O!M!.!~!8! +,!M#D!?!M#D! #.!Z!M#,!Z!?! !~!N! "N!.! !M! +
2513 'D!:! %$!D! !?! #M!Z! !8!.! !M"?!7!?!7! '+!I!D! !?!O!:!M!:! ":!M!:! !M!7".!M! "8!+! !:!D! !.!M! *
2514 %.!O!:! $.!O!+! !D!.! #M! "M!.!+!N!I!Z! "7!M!N!M!N!?!I!7!Z!=!M'D"~! #M!.!8!$! !:! !.!M! "N!?! !,!O! )
2515 !.!?!M!:!M!I! %8!,! "M!.! #M! "N! !M!.! !M!.! !+!~! !.!M!.! ':!M! $M! $M!Z!$! !M!.! "D! "M! "?!M! (
2516 !7!8! !+!I! ".! "$!=! ":!$! "+! !M!.! !O! !M!I!M".! !=!~! ",!O! '=!M! $$!,! #N!:! ":!8!.! !D!~! !,!M!.! !:!M!.! &
2517 !:!,!.! &Z" #D! !.!8!."M!.! !8!?!Z!M!.!M! #Z!~! !?!M!Z!.! %~!O!.!8!$!N!8!O!I!:!~! !+! #M!.! !.!M!.! !+!M! ".!~!M!+! $
2518 !.! 'D!I! #?!M!.!M!,! !.!Z! !.!8! #M&O!I!?! (~!I!M"." !M!Z!.! !M!N!.! "+!$!.! "M!.! !M!?!.! "8!M! $
2519 (O!8! $M! !M!.! ".!:! !+!=! #M! #.!M! !+" *$!M":!.! !M!~! "M!7! #M! #7!Z! "M"$!M!.! !.! #
2520 '$!Z! #.!7!+!M! $.!,! !+!:! #N! #.!M!.!+!M! +D!M! #=!N! ":!O! #=!M! #Z!D! $M!I! %
2521 $,! ".! $.!M" %$!.! !?!~! "+!7!." !.!M!,! !M! *,!N!M!.$M!?! "D!,! #M!.! #N! +
2522 ,M!Z! &M! "I!,! "M! %I!M! !?!=!.! (Z!8!M! $:!M!.! !,!M! $D! #.!M!.! )
2523 +8!O! &.!8! "I!,! !~!M! &N!M! !M!D! '?!N!O!." $?!7! "?!~! #M!.! #I!D!.! (
2524 3M!,! "N!.! !D" &.!+!M!.! !M":!.":!M!7!M!D! 'M!.! "M!.! "M!,! $I! )
2525 3I! #M! "M!,! !:! &.!M" ".!,! !.!$!M!I! #.! !:! !.!M!?! "N!+! ".! /
2526 1M!,! #.!M!8!M!=!.! +~!N"O!Z"~! *+!M!.! "M! 2
2527 0.!M! &M!.! 8:! %.!M!Z! "M!=! *O!,! %
2528 0?!$! &N! )." .,! %."M! ":!M!.! 0
2529 0N!:! %?!O! #.! ..! &,! &.!D!,! "N!I! 0
2530 CATHY
2531 return App::Ack::__pic($x);
2534 sub __pic {
2535 my($compressed) = @_;
2536 $compressed =~ s/(.)(.)/$1x(ord($2)-32)/eg;
2537 App::Ack::print( $compressed );
2538 exit 0;
2542 sub show_help {
2543 my $help_arg = shift || 0;
2545 return show_help_types() if $help_arg =~ /^types?/;
2547 App::Ack::print( <<"END_OF_HELP" );
2548 Usage: ack [OPTION]... PATTERN [FILES OR DIRECTORIES]
2550 Search for PATTERN in each source file in the tree from the current
2551 directory on down. If any files or directories are specified, then
2552 only those files and directories are checked. ack may also search
2553 STDIN, but only if no file or directory arguments are specified,
2554 or if one of them is "-".
2556 Default switches may be specified in ACK_OPTIONS environment variable or
2557 an .ackrc file. If you want no dependency on the environment, turn it
2558 off with --noenv.
2560 Example: ack -i select
2562 Searching:
2563 -i, --ignore-case Ignore case distinctions in PATTERN
2564 --[no]smart-case Ignore case distinctions in PATTERN,
2565 only if PATTERN contains no upper case.
2566 Ignored if -i is specified
2567 -v, --invert-match Invert match: select non-matching lines
2568 -w, --word-regexp Force PATTERN to match only whole words
2569 -Q, --literal Quote all metacharacters; PATTERN is literal
2571 Search output:
2572 --lines=NUM Only print line(s) NUM of each file
2573 -l, --files-with-matches Only print filenames containing matches
2574 -L, --files-without-matches Only print filenames with no matches
2575 --output=expr Output the evaluation of expr for each line
2576 (turns off text highlighting)
2577 -o Show only the part of a line matching PATTERN
2578 Same as --output='\$&'
2579 --passthru Print all lines, whether matching or not
2580 --match PATTERN Specify PATTERN explicitly.
2581 -m, --max-count=NUM Stop searching in each file after NUM matches
2582 -1 Stop searching after one match of any kind
2583 -H, --with-filename Print the filename for each match (default:
2584 on unless explicitly searching a single file)
2585 -h, --no-filename Suppress the prefixing filename on output
2586 -c, --count Show number of lines matching per file
2587 --[no]column Show the column number of the first match
2589 -A NUM, --after-context=NUM Print NUM lines of trailing context after
2590 matching lines.
2591 -B NUM, --before-context=NUM Print NUM lines of leading context before
2592 matching lines.
2593 -C [NUM], --context[=NUM] Print NUM lines (default 2) of output context.
2595 --print0 Print null byte as separator between filenames,
2596 only works with -f, -g, -l, -L or -c.
2598 -s Suppress error messages about nonexistent or
2599 unreadable files.
2602 File presentation:
2603 --pager=COMMAND Pipes all ack output through COMMAND. For
2604 example, --pager="less -R". Ignored if output
2605 is redirected.
2606 --nopager Do not send output through a pager. Cancels
2607 any setting in ~/.ackrc, ACK_PAGER or
2608 ACK_PAGER_COLOR.
2609 --[no]heading Print a filename heading above each file's
2610 results. (default: on when used interactively)
2611 --[no]break Print a break between results from different
2612 files. (default: on when used interactively)
2613 --group Same as --heading --break
2614 --nogroup Same as --noheading --nobreak
2615 --[no]color Highlight the matching text (default: on unless
2616 output is redirected, or on Windows)
2617 --[no]colour Same as --[no]color
2618 --color-filename=COLOR
2619 --color-match=COLOR
2620 --color-lineno=COLOR Set the color for filenames, matches, and line
2621 numbers.
2622 --flush Flush output immediately, even when ack is used
2623 non-interactively (when output goes to a pipe or
2624 file).
2627 File finding:
2628 -f Only print the files selected, without
2629 searching. The PATTERN must not be specified.
2630 -g Same as -f, but only select files matching
2631 PATTERN.
2632 --sort-files Sort the found files lexically.
2633 --show-types Show which types each file has.
2634 --files-from=FILE Read the list of files to search from FILE.
2635 -x Read the list of files to search from STDIN.
2637 File inclusion/exclusion:
2638 --[no]ignore-dir=name Add/remove directory from list of ignored dirs
2639 --[no]ignore-directory=name Synonym for ignore-dir
2640 --ignore-file=filter Add filter for ignoring files
2641 -r, -R, --recurse Recurse into subdirectories (default: on)
2642 -n, --no-recurse No descending into subdirectories
2643 --[no]follow Follow symlinks. Default is off.
2644 -k, --known-types Include only files of types that ack recognizes.
2646 --type=X Include only X files, where X is a recognized
2647 filetype.
2648 --type=noX Exclude X files.
2649 See "ack --help-types" for supported filetypes.
2651 File type specification:
2652 --type-set TYPE:FILTER:FILTERARGS
2653 Files with the given FILTERARGS applied to the
2654 given FILTER are recognized as being of type
2655 TYPE. This replaces an existing definition for
2656 type TYPE.
2657 --type-add TYPE:FILTER:FILTERARGS
2658 Files with the given FILTERARGS applied to the
2659 given FILTER are recognized as being type TYPE.
2660 --type-del TYPE Removes all filters associated with TYPE.
2663 Miscellaneous:
2664 --[no]env Ignore environment variables and global ackrc
2665 files. --env is legal but redundant.
2666 --ackrc=filename Specify an ackrc file to use
2667 --ignore-ack-defaults Ignore default definitions included with ack.
2668 --create-ackrc Outputs a default ackrc for your customization
2669 to standard output.
2670 --help, -? This help
2671 --help-types Display all known types
2672 --dump Dump information on which options are loaded
2673 from which RC files
2674 --[no]filter Force ack to treat standard input as a pipe
2675 (--filter) or tty (--nofilter)
2676 --man Man page
2677 --version Display version & copyright
2678 --thpppt Bill the Cat
2679 --bar The warning admiral
2680 --cathy Chocolate! Chocolate! Chocolate!
2682 Exit status is 0 if match, 1 if no match.
2684 ack's home page is at http://beyondgrep.com/
2686 The full ack manual is available by running "ack --man".
2688 This is version $VERSION of ack. Run "ack --version" for full version info.
2689 END_OF_HELP
2691 return;
2696 sub show_help_types {
2697 App::Ack::print( <<'END_OF_HELP' );
2698 Usage: ack [OPTION]... PATTERN [FILES OR DIRECTORIES]
2700 The following is the list of filetypes supported by ack. You can
2701 specify a file type with the --type=TYPE format, or the --TYPE
2702 format. For example, both --type=perl and --perl work.
2704 Note that some extensions may appear in multiple types. For example,
2705 .pod files are both Perl and Parrot.
2707 END_OF_HELP
2709 my @types = filetypes_supported();
2710 my $maxlen = 0;
2711 for ( @types ) {
2712 $maxlen = length if $maxlen < length;
2714 for my $type ( sort @types ) {
2715 next if $type =~ /^-/; # Stuff to not show
2716 my $ext_list = $mappings{$type};
2718 if ( ref $ext_list ) {
2719 $ext_list = join( '; ', map { $_->to_string } @{$ext_list} );
2721 App::Ack::print( sprintf( " --[no]%-*.*s %s\n", $maxlen, $maxlen, $type, $ext_list ) );
2724 return;
2727 sub show_man {
2728 require Pod::Usage;
2730 Pod::Usage::pod2usage({
2731 -input => $App::Ack::orig_program_name,
2732 -verbose => 2,
2733 -exitval => 0,
2736 return;
2740 sub get_version_statement {
2741 require Config;
2743 my $copyright = get_copyright();
2744 my $this_perl = $Config::Config{perlpath};
2745 if ($^O ne 'VMS') {
2746 my $ext = $Config::Config{_exe};
2747 $this_perl .= $ext unless $this_perl =~ m/$ext$/i;
2749 my $ver = sprintf( '%vd', $^V );
2751 return <<"END_OF_VERSION";
2752 ack ${VERSION}
2753 Running under Perl $ver at $this_perl
2755 $copyright
2757 This program is free software. You may modify or distribute it
2758 under the terms of the Artistic License v2.0.
2759 END_OF_VERSION
2763 sub print_version_statement {
2764 App::Ack::print( get_version_statement() );
2766 return;
2770 sub get_copyright {
2771 return $COPYRIGHT;
2775 # print*() subs added in order to make it easy for a third party
2776 # module (such as App::Wack) to redefine the display methods
2777 # and show the results in a different way.
2778 sub print { print {$fh} @_; return; }
2779 sub print_first_filename { App::Ack::print( $_[0], "\n" ); return; }
2780 sub print_blank_line { App::Ack::print( "\n" ); return; }
2781 sub print_separator { App::Ack::print( "--\n" ); return; }
2782 sub print_filename { App::Ack::print( $_[0], $_[1] ); return; }
2783 sub print_line_no { App::Ack::print( $_[0], $_[1] ); return; }
2784 sub print_column_no { App::Ack::print( $_[0], $_[1] ); return; }
2785 sub print_count {
2786 my $filename = shift;
2787 my $nmatches = shift;
2788 my $ors = shift;
2789 my $count = shift;
2790 my $show_filename = shift;
2792 if ($show_filename) {
2793 App::Ack::print( $filename );
2794 App::Ack::print( ':', $nmatches ) if $count;
2796 else {
2797 App::Ack::print( $nmatches ) if $count;
2799 App::Ack::print( $ors );
2801 return;
2804 sub print_count0 {
2805 my $filename = shift;
2806 my $ors = shift;
2807 my $show_filename = shift;
2809 if ($show_filename) {
2810 App::Ack::print( $filename, ':0', $ors );
2812 else {
2813 App::Ack::print( '0', $ors );
2816 return;
2819 sub set_up_pager {
2820 my $command = shift;
2822 return if App::Ack::output_to_pipe();
2824 my $pager;
2825 if ( not open( $pager, '|-', $command ) ) {
2826 App::Ack::die( qq{Unable to pipe to pager "$command": $!} );
2828 $fh = $pager;
2830 return;
2834 sub output_to_pipe {
2835 return $output_to_pipe;
2839 sub exit_from_ack {
2840 my $nmatches = shift;
2842 my $rc = $nmatches ? 0 : 1;
2843 exit $rc;
2848 1; # End of App::Ack
2849 package App::Ack::Resource;
2852 use warnings;
2853 use strict;
2854 use overload
2855 '""' => 'name';
2857 sub FAIL {
2858 require Carp;
2859 Carp::confess( 'Must be overloaded' );
2863 sub new {
2864 return FAIL();
2868 sub name {
2869 return FAIL();
2873 sub is_binary {
2874 return FAIL();
2878 sub open {
2879 return FAIL();
2883 sub needs_line_scan {
2884 return FAIL();
2888 sub reset {
2889 return FAIL();
2893 sub close {
2894 return FAIL();
2898 sub clone {
2899 return FAIL();
2903 sub firstliney {
2904 return FAIL();
2908 package App::Ack::Resources;
2912 use warnings;
2913 use strict;
2915 sub _generate_error_handler {
2916 my $opt = shift;
2918 if ( $opt->{dont_report_bad_filenames} ) {
2919 return sub {
2920 my $msg = shift;
2921 # XXX restricting to specific error messages for now; I would
2922 # prefer a different way of doing this
2923 if ( $msg =~ /Permission denied/ ) {
2924 return;
2926 App::Ack::warn( $msg );
2929 else {
2930 return sub {
2931 my $msg = shift;
2932 App::Ack::warn( $msg );
2938 sub from_argv {
2939 my $class = shift;
2940 my $opt = shift;
2941 my $start = shift;
2943 my $self = bless {}, $class;
2945 my $file_filter = undef;
2946 my $descend_filter = $opt->{descend_filter};
2948 if( $opt->{n} ) {
2949 $descend_filter = sub {
2950 return 0;
2954 $self->{iter} =
2955 File::Next::files( {
2956 file_filter => $opt->{file_filter},
2957 descend_filter => $descend_filter,
2958 error_handler => _generate_error_handler($opt),
2959 warning_handler => sub {},
2960 sort_files => $opt->{sort_files},
2961 follow_symlinks => $opt->{follow},
2962 }, @{$start} );
2964 return $self;
2968 sub from_file {
2969 my $class = shift;
2970 my $opt = shift;
2971 my $file = shift;
2973 my $iter =
2974 File::Next::from_file( {
2975 error_handler => _generate_error_handler($opt),
2976 warning_handler => _generate_error_handler($opt),
2977 sort_files => $opt->{sort_files},
2978 }, $file ) or return undef;
2980 return bless {
2981 iter => $iter,
2982 }, $class;
2985 # This is for reading input lines from STDIN, not the list of files from STDIN
2986 sub from_stdin {
2987 my $class = shift;
2988 my $opt = shift;
2990 my $self = bless {}, $class;
2992 my $has_been_called = 0;
2994 $self->{iter} = sub {
2995 if ( !$has_been_called ) {
2996 $has_been_called = 1;
2997 return '-';
2999 return;
3002 return $self;
3005 sub next {
3006 my $self = shift;
3008 my $file = $self->{iter}->() or return;
3010 return App::Ack::Resource::Basic->new( $file );
3014 package App::Ack::Resource::Basic;
3017 use warnings;
3018 use strict;
3020 use Fcntl ();
3022 BEGIN {
3023 our @ISA = 'App::Ack::Resource';
3028 sub new {
3029 my $class = shift;
3030 my $filename = shift;
3032 my $self = bless {
3033 filename => $filename,
3034 fh => undef,
3035 opened => 0,
3036 }, $class;
3038 if ( $self->{filename} eq '-' ) {
3039 $self->{fh} = *STDIN;
3040 $self->{opened} = 1;
3043 return $self;
3047 sub name {
3048 return $_[0]->{filename};
3053 sub needs_line_scan {
3054 my $self = shift;
3055 my $opt = shift;
3057 return 1 if $opt->{v};
3059 my $size = -s $self->{fh};
3060 if ( $size == 0 ) {
3061 return 0;
3063 elsif ( $size > 100_000 ) {
3064 return 1;
3067 my $buffer;
3068 my $rc = sysread( $self->{fh}, $buffer, $size );
3069 if ( !defined($rc) && $App::Ack::report_bad_filenames ) {
3070 App::Ack::warn( "$self->{filename}: $!" );
3071 return 1;
3073 return 0 unless $rc && ( $rc == $size );
3075 my $regex = $opt->{regex};
3076 return $buffer =~ /$regex/m;
3080 sub reset {
3081 my $self = shift;
3083 # return if we haven't opened the file yet
3084 if ( !defined($self->{fh}) ) {
3085 return;
3088 if( !seek( $self->{fh}, 0, 0 ) && $App::Ack::report_bad_filenames ) {
3089 App::Ack::warn( "$self->{filename}: $!" );
3092 return;
3096 sub close {
3097 my $self = shift;
3099 # return if we haven't opened the file yet
3100 if ( !defined($self->{fh}) ) {
3101 return;
3104 if ( !close($self->{fh}) && $App::Ack::report_bad_filenames ) {
3105 App::Ack::warn( $self->name() . ": $!" );
3108 $self->{opened} = 0;
3110 return;
3114 sub clone {
3115 my ( $self ) = @_;
3117 return __PACKAGE__->new($self->name);
3120 sub firstliney {
3121 my ( $self ) = @_;
3123 my $fh = $self->open();
3125 if ( !exists $self->{firstliney} ) {
3126 my $buffer = '';
3127 my $rc = sysread( $fh, $buffer, 250 );
3128 unless($rc) { # XXX handle this better?
3129 $buffer = '';
3131 $buffer =~ s/[\r\n].*//s;
3132 $self->{firstliney} = $buffer;
3133 $self->reset;
3136 $self->close;
3138 return $self->{firstliney};
3141 sub open {
3142 my ( $self ) = @_;
3144 return $self->{fh} if $self->{opened};
3146 if ( ! open $self->{fh}, '<', $self->{filename} ) {
3147 return;
3150 $self->{opened} = 1;
3152 return $self->{fh};
3156 package App::Ack::ConfigDefault;
3158 use warnings;
3159 use strict;
3163 sub options {
3164 return split( /\n/, _options_block() );
3168 sub options_clean {
3169 return grep { /./ && !/^#/ } options();
3173 sub _options_block {
3174 my $lines = <<'HERE';
3175 # This is the default ackrc for ack version ==VERSION==.
3177 # There are four different ways to match
3179 # is: Match the filename exactly
3181 # ext: Match the extension of the filename exactly
3183 # match: Match the filename against a Perl regular expression
3185 # firstlinematch: Match the first 250 characters of the first line
3186 # of text against a Perl regular expression. This is only for
3187 # the --type-add option.
3190 ### Directories to ignore
3192 # Bazaar
3193 # http://bazaar.canonical.com/
3194 --ignore-directory=is:.bzr
3196 # Codeville
3197 # http://freecode.com/projects/codeville
3198 --ignore-directory=is:.cdv
3200 # Interface Builder (Xcode)
3201 # http://en.wikipedia.org/wiki/Interface_Builder
3202 --ignore-directory=is:~.dep
3203 --ignore-directory=is:~.dot
3204 --ignore-directory=is:~.nib
3205 --ignore-directory=is:~.plst
3207 # Git
3208 # http://git-scm.com/
3209 --ignore-directory=is:.git
3211 # Mercurial
3212 # http://mercurial.selenic.com/
3213 --ignore-directory=is:.hg
3215 # quilt
3216 # http://directory.fsf.org/wiki/Quilt
3217 --ignore-directory=is:.pc
3219 # Subversion
3220 # http://subversion.tigris.org/
3221 --ignore-directory=is:.svn
3223 # Monotone
3224 # http://www.monotone.ca/
3225 --ignore-directory=is:_MTN
3227 # CVS
3228 # http://savannah.nongnu.org/projects/cvs
3229 --ignore-directory=is:CVS
3231 # RCS
3232 # http://www.gnu.org/software/rcs/
3233 --ignore-directory=is:RCS
3235 # SCCS
3236 # http://en.wikipedia.org/wiki/Source_Code_Control_System
3237 --ignore-directory=is:SCCS
3239 # darcs
3240 # http://darcs.net/
3241 --ignore-directory=is:_darcs
3243 # Vault/Fortress
3244 --ignore-directory=is:_sgbak
3246 # autoconf
3247 # http://www.gnu.org/software/autoconf/
3248 --ignore-directory=is:autom4te.cache
3250 # Perl module building
3251 --ignore-directory=is:blib
3252 --ignore-directory=is:_build
3254 # Perl Devel::Cover module's output directory
3255 # https://metacpan.org/release/Devel-Cover
3256 --ignore-directory=is:cover_db
3258 # Node modules created by npm
3259 --ignore-directory=is:node_modules
3261 # CMake cache
3262 # http://www.cmake.org/
3263 --ignore-directory=is:CMakeFiles
3265 # Eclipse workspace folder
3266 # http://eclipse.org/
3267 --ignore-directory=is:.metadata
3269 # Cabal (Haskell) sandboxes
3270 # http://www.haskell.org/cabal/users-guide/installing-packages.html
3271 --ignore-directory=is:.cabal-sandbox
3273 ### Files to ignore
3275 # Backup files
3276 --ignore-file=ext:bak
3277 --ignore-file=match:/~$/
3279 # Emacs swap files
3280 --ignore-file=match:/^#.+#$/
3282 # vi/vim swap files http://vim.org/
3283 --ignore-file=match:/[._].*\.swp$/
3285 # core dumps
3286 --ignore-file=match:/core\.\d+$/
3288 # minified Javascript
3289 --ignore-file=match:/[.-]min[.]js$/
3290 --ignore-file=match:/[.]js[.]min$/
3292 # minified CSS
3293 --ignore-file=match:/[.]min[.]css$/
3294 --ignore-file=match:/[.]css[.]min$/
3296 # JS and CSS source maps
3297 --ignore-file=match:/[.]js[.]map$/
3298 --ignore-file=match:/[.]css[.]map$/
3300 # PDFs, because they pass Perl's -T detection
3301 --ignore-file=ext:pdf
3303 # Common graphics, just as an optimization
3304 --ignore-file=ext:gif,jpg,jpeg,png
3307 ### Filetypes defined
3309 # Perl
3310 # http://perl.org/
3311 --type-add=perl:ext:pl,pm,pod,t,psgi
3312 --type-add=perl:firstlinematch:/^#!.*\bperl/
3314 # Perl tests
3315 --type-add=perltest:ext:t
3317 # Makefiles
3318 # http://www.gnu.org/s/make/
3319 --type-add=make:ext:mk
3320 --type-add=make:ext:mak
3321 --type-add=make:is:makefile
3322 --type-add=make:is:Makefile
3323 --type-add=make:is:Makefile.Debug
3324 --type-add=make:is:Makefile.Release
3326 # Rakefiles
3327 # http://rake.rubyforge.org/
3328 --type-add=rake:is:Rakefile
3330 # CMake
3331 # http://www.cmake.org/
3332 --type-add=cmake:is:CMakeLists.txt
3333 --type-add=cmake:ext:cmake
3335 # Actionscript
3336 --type-add=actionscript:ext:as,mxml
3338 # Ada
3339 # http://www.adaic.org/
3340 --type-add=ada:ext:ada,adb,ads
3342 # ASP
3343 # http://msdn.microsoft.com/en-us/library/aa286483.aspx
3344 --type-add=asp:ext:asp
3346 # ASP.Net
3347 # http://www.asp.net/
3348 --type-add=aspx:ext:master,ascx,asmx,aspx,svc
3350 # Assembly
3351 --type-add=asm:ext:asm,s
3353 # Batch
3354 --type-add=batch:ext:bat,cmd
3356 # ColdFusion
3357 # http://en.wikipedia.org/wiki/ColdFusion
3358 --type-add=cfmx:ext:cfc,cfm,cfml
3360 # Clojure
3361 # http://clojure.org/
3362 --type-add=clojure:ext:clj
3365 # .xs are Perl C files
3366 --type-add=cc:ext:c,h,xs
3368 # C header files
3369 --type-add=hh:ext:h
3371 # CoffeeScript
3372 # http://coffeescript.org/
3373 --type-add=coffeescript:ext:coffee
3375 # C++
3376 --type-add=cpp:ext:cpp,cc,cxx,m,hpp,hh,h,hxx
3378 # C#
3379 --type-add=csharp:ext:cs
3381 # CSS
3382 # http://www.w3.org/Style/CSS/
3383 --type-add=css:ext:css
3385 # Dart
3386 # http://www.dartlang.org/
3387 --type-add=dart:ext:dart
3389 # Delphi
3390 # http://en.wikipedia.org/wiki/Embarcadero_Delphi
3391 --type-add=delphi:ext:pas,int,dfm,nfm,dof,dpk,dproj,groupproj,bdsgroup,bdsproj
3393 # Elixir
3394 # http://elixir-lang.org/
3395 --type-add=elixir:ext:ex,exs
3397 # Emacs Lisp
3398 # http://www.gnu.org/software/emacs
3399 --type-add=elisp:ext:el
3401 # Erlang
3402 # http://www.erlang.org/
3403 --type-add=erlang:ext:erl,hrl
3405 # Fortran
3406 # http://en.wikipedia.org/wiki/Fortran
3407 --type-add=fortran:ext:f,f77,f90,f95,f03,for,ftn,fpp
3409 # Go
3410 # http://golang.org/
3411 --type-add=go:ext:go
3413 # Groovy
3414 # http://groovy.codehaus.org/
3415 --type-add=groovy:ext:groovy,gtmpl,gpp,grunit,gradle
3417 # Haskell
3418 # http://www.haskell.org/
3419 --type-add=haskell:ext:hs,lhs
3421 # HTML
3422 --type-add=html:ext:htm,html
3424 # Jade
3425 # http://jade-lang.com/
3426 --type-add=jade:ext:jade
3428 # Java
3429 # http://www.oracle.com/technetwork/java/index.html
3430 --type-add=java:ext:java,properties
3432 # JavaScript
3433 --type-add=js:ext:js
3435 # JSP
3436 # http://www.oracle.com/technetwork/java/javaee/jsp/index.html
3437 --type-add=jsp:ext:jsp,jspx,jhtm,jhtml
3439 # JSON
3440 # http://www.json.org/
3441 --type-add=json:ext:json
3443 # Less
3444 # http://www.lesscss.org/
3445 --type-add=less:ext:less
3447 # Common Lisp
3448 # http://common-lisp.net/
3449 --type-add=lisp:ext:lisp,lsp
3451 # Lua
3452 # http://www.lua.org/
3453 --type-add=lua:ext:lua
3454 --type-add=lua:firstlinematch:/^#!.*\blua(jit)?/
3456 # Objective-C
3457 --type-add=objc:ext:m,h
3459 # Objective-C++
3460 --type-add=objcpp:ext:mm,h
3462 # OCaml
3463 # http://caml.inria.fr/
3464 --type-add=ocaml:ext:ml,mli
3466 # Matlab
3467 # http://en.wikipedia.org/wiki/MATLAB
3468 --type-add=matlab:ext:m
3470 # Parrot
3471 # http://www.parrot.org/
3472 --type-add=parrot:ext:pir,pasm,pmc,ops,pod,pg,tg
3474 # PHP
3475 # http://www.php.net/
3476 --type-add=php:ext:php,phpt,php3,php4,php5,phtml
3477 --type-add=php:firstlinematch:/^#!.*\bphp/
3479 # Plone
3480 # http://plone.org/
3481 --type-add=plone:ext:pt,cpt,metadata,cpy,py
3483 # Python
3484 # http://www.python.org/
3485 --type-add=python:ext:py
3486 --type-add=python:firstlinematch:/^#!.*\bpython/
3489 # http://www.r-project.org/
3490 --type-add=rr:ext:R
3492 # reStructured Text
3493 # http://docutils.sourceforge.net/rst.html
3494 --type-add=rst:ext:rst
3496 # Ruby
3497 # http://www.ruby-lang.org/
3498 --type-add=ruby:ext:rb,rhtml,rjs,rxml,erb,rake,spec
3499 --type-add=ruby:is:Rakefile
3500 --type-add=ruby:firstlinematch:/^#!.*\bruby/
3502 # Rust
3503 # http://www.rust-lang.org/
3504 --type-add=rust:ext:rs
3506 # Sass
3507 # http://sass-lang.com
3508 --type-add=sass:ext:sass,scss
3510 # Scala
3511 # http://www.scala-lang.org/
3512 --type-add=scala:ext:scala
3514 # Scheme
3515 # http://groups.csail.mit.edu/mac/projects/scheme/
3516 --type-add=scheme:ext:scm,ss
3518 # Shell
3519 --type-add=shell:ext:sh,bash,csh,tcsh,ksh,zsh,fish
3520 --type-add=shell:firstlinematch:/^#!.*\b(?:ba|t?c|k|z|fi)?sh\b/
3522 # Smalltalk
3523 # http://www.smalltalk.org/
3524 --type-add=smalltalk:ext:st
3526 # Smarty
3527 # http://www.smarty.net/
3528 --type-add=smarty:ext:tpl
3530 # SQL
3531 # http://www.iso.org/iso/catalogue_detail.htm?csnumber=45498
3532 --type-add=sql:ext:sql,ctl
3534 # Stylus
3535 # http://learnboost.github.io/stylus/
3536 --type-add=stylus:ext:styl
3538 # Tcl
3539 # http://www.tcl.tk/
3540 --type-add=tcl:ext:tcl,itcl,itk
3542 # LaTeX
3543 # http://www.latex-project.org/
3544 --type-add=tex:ext:tex,cls,sty
3546 # Template Toolkit (Perl)
3547 # http://template-toolkit.org/
3548 --type-add=tt:ext:tt,tt2,ttml
3550 # Visual Basic
3551 --type-add=vb:ext:bas,cls,frm,ctl,vb,resx
3553 # Verilog
3554 --type-add=verilog:ext:v,vh,sv
3556 # VHDL
3557 # http://www.eda.org/twiki/bin/view.cgi/P1076/WebHome
3558 --type-add=vhdl:ext:vhd,vhdl
3560 # Vim
3561 # http://www.vim.org/
3562 --type-add=vim:ext:vim
3564 # XML
3565 # http://www.w3.org/TR/REC-xml/
3566 --type-add=xml:ext:xml,dtd,xsl,xslt,ent
3567 --type-add=xml:firstlinematch:/<[?]xml/
3569 # YAML
3570 # http://yaml.org/
3571 --type-add=yaml:ext:yaml,yml
3572 HERE
3573 $lines =~ s/==VERSION==/$App::Ack::VERSION/sm;
3575 return $lines;
3579 package App::Ack::ConfigFinder;
3582 use strict;
3583 use warnings;
3585 use Cwd 3.00 ();
3586 use File::Spec 3.00;
3588 use if ($^O eq 'MSWin32'), 'Win32';
3591 sub new {
3592 my ( $class ) = @_;
3594 return bless {}, $class;
3598 sub _remove_redundancies {
3599 my @configs = @_;
3601 my %seen;
3602 foreach my $config (@configs) {
3603 my $key = $config->{path};
3604 if ( not $App::Ack::is_windows ) {
3605 # On Unix, uniquify on inode.
3606 my ($dev, $inode) = (stat $key)[0, 1];
3607 $key = "$dev:$inode" if defined $dev;
3609 undef $config if $seen{$key}++;
3611 return grep { defined } @configs;
3615 sub _check_for_ackrc {
3616 return unless defined $_[0];
3618 my @files = grep { -f }
3619 map { File::Spec->catfile(@_, $_) }
3620 qw(.ackrc _ackrc);
3622 die File::Spec->catdir(@_) . " contains both .ackrc and _ackrc.\n" .
3623 "Please remove one of those files.\n"
3624 if @files > 1;
3626 return wantarray ? @files : $files[0];
3627 } # end _check_for_ackrc
3631 sub find_config_files {
3632 my @config_files;
3634 if ( $App::Ack::is_windows ) {
3635 push @config_files, map { +{ path => File::Spec->catfile($_, 'ackrc') } } (
3636 Win32::GetFolderPath(Win32::CSIDL_COMMON_APPDATA()),
3637 Win32::GetFolderPath(Win32::CSIDL_APPDATA()),
3640 else {
3641 push @config_files, { path => '/etc/ackrc' };
3645 if ( $ENV{'ACKRC'} && -f $ENV{'ACKRC'} ) {
3646 push @config_files, { path => $ENV{'ACKRC'} };
3648 else {
3649 push @config_files, map { +{ path => $_ } } _check_for_ackrc($ENV{'HOME'});
3652 # XXX This should go through some untainted cwd-fetching function, and not get untainted inline like this.
3653 my $cwd = Cwd::getcwd();
3654 $cwd =~ /(.+)/;
3655 $cwd = $1;
3656 my @dirs = File::Spec->splitdir( $cwd );
3657 while(@dirs) {
3658 my $ackrc = _check_for_ackrc(@dirs);
3659 if(defined $ackrc) {
3660 push @config_files, { project => 1, path => $ackrc };
3661 last;
3663 pop @dirs;
3666 # We only test for existence here, so if the file is deleted out from under us, this will fail later.
3667 return _remove_redundancies( @config_files );
3672 sub read_rcfile {
3673 my $file = shift;
3675 return unless defined $file && -e $file;
3677 my @lines;
3679 open( my $fh, '<', $file ) or App::Ack::die( "Unable to read $file: $!" );
3680 while ( my $line = <$fh> ) {
3681 chomp $line;
3682 $line =~ s/^\s+//;
3683 $line =~ s/\s+$//;
3685 next if $line eq '';
3686 next if $line =~ /^\s*#/;
3688 push( @lines, $line );
3690 close $fh or App::Ack::die( "Unable to close $file: $!" );
3692 return @lines;
3696 package App::Ack::ConfigLoader;
3698 use strict;
3699 use warnings;
3701 use Carp 1.04 ();
3702 use Getopt::Long 2.35 ();
3703 use Text::ParseWords 3.1 ();
3706 my @INVALID_COMBINATIONS;
3708 BEGIN {
3709 my @context = qw( -A -B -C --after-context --before-context --context );
3710 my @pretty = qw( --heading --group --break );
3711 my @filename = qw( -h -H --with-filename --no-filename );
3713 @INVALID_COMBINATIONS = (
3714 # XXX normalize
3715 [qw(-l)] => [@context, @pretty, @filename, qw(-L -o --passthru --output --max-count --column -f -g --show-types)],
3716 [qw(-L)] => [@context, @pretty, @filename, qw(-l -o --passthru --output --max-count --column -f -g --show-types -c --count)],
3717 [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)],
3718 [qw(-o)] => [@context, qw(--output -c --count --column --column -f --show-types)],
3719 [qw(--passthru)] => [@context, qw(--output --column -m --max-count -1 -c --count -f -g)],
3720 [qw(--output)] => [@context, qw(-c --count -f -g)],
3721 [qw(--match)] => [qw(-f -g)],
3722 [qw(-m --max-count)] => [qw(-1 -f -g -c --count)],
3723 [qw(-h --no-filename)] => [qw(-H --with-filename -f -g --group --heading)],
3724 [qw(-H --with-filename)] => [qw(-h --no-filename -f -g)],
3725 [qw(-c --count)] => [@context, @pretty, qw(--column -f -g)],
3726 [qw(--column)] => [qw(-f -g)],
3727 [@context] => [qw(-f -g)],
3728 [qw(-f)] => [qw(-g), @pretty],
3729 [qw(-g)] => [qw(-f), @pretty],
3734 sub process_filter_spec {
3735 my ( $spec ) = @_;
3737 if ( $spec =~ /^(\w+):(\w+):(.*)/ ) {
3738 my ( $type_name, $ext_type, $arguments ) = ( $1, $2, $3 );
3740 return ( $type_name,
3741 App::Ack::Filter->create_filter($ext_type, split(/,/, $arguments)) );
3743 elsif ( $spec =~ /^(\w+)=(.*)/ ) { # Check to see if we have ack1-style argument specification.
3744 my ( $type_name, $extensions ) = ( $1, $2 );
3746 my @extensions = split(/,/, $extensions);
3747 foreach my $extension ( @extensions ) {
3748 $extension =~ s/^[.]//;
3751 return ( $type_name, App::Ack::Filter->create_filter('ext', @extensions) );
3753 else {
3754 Carp::croak "invalid filter specification '$spec'";
3759 sub uninvert_filter {
3760 my ( $opt, @filters ) = @_;
3762 return unless defined $opt->{filters} && @filters;
3764 # Loop through all the registered filters. If we hit one that
3765 # matches this extension and it's inverted, we need to delete it from
3766 # the options.
3767 for ( my $i = 0; $i < @{ $opt->{filters} }; $i++ ) {
3768 my $opt_filter = @{ $opt->{filters} }[$i];
3770 # XXX Do a real list comparison? This just checks string equivalence.
3771 if ( $opt_filter->is_inverted() && "$opt_filter->{filter}" eq "@filters" ) {
3772 splice @{ $opt->{filters} }, $i, 1;
3773 $i--;
3779 sub process_filetypes {
3780 my ( $opt, $arg_sources ) = @_;
3782 Getopt::Long::Configure('default', 'no_auto_help', 'no_auto_version'); # start with default options, minus some annoying ones
3783 Getopt::Long::Configure(
3784 'no_ignore_case',
3785 'no_auto_abbrev',
3786 'pass_through',
3788 my %additional_specs;
3790 my $add_spec = sub {
3791 my ( undef, $spec ) = @_;
3793 my ( $name, $filter ) = process_filter_spec($spec);
3795 push @{ $App::Ack::mappings{$name} }, $filter;
3797 $additional_specs{$name . '!'} = sub {
3798 my ( undef, $value ) = @_;
3800 my @filters = @{ $App::Ack::mappings{$name} };
3801 if ( not $value ) {
3802 @filters = map { $_->invert() } @filters;
3804 else {
3805 uninvert_filter( $opt, @filters );
3808 push @{ $opt->{'filters'} }, @filters;
3812 my $set_spec = sub {
3813 my ( undef, $spec ) = @_;
3815 my ( $name, $filter ) = process_filter_spec($spec);
3817 $App::Ack::mappings{$name} = [ $filter ];
3819 $additional_specs{$name . '!'} = sub {
3820 my ( undef, $value ) = @_;
3822 my @filters = @{ $App::Ack::mappings{$name} };
3823 if ( not $value ) {
3824 @filters = map { $_->invert() } @filters;
3827 push @{ $opt->{'filters'} }, @filters;
3831 my $delete_spec = sub {
3832 my ( undef, $name ) = @_;
3834 delete $App::Ack::mappings{$name};
3835 delete $additional_specs{$name . '!'};
3838 my %type_arg_specs = (
3839 'type-add=s' => $add_spec,
3840 'type-set=s' => $set_spec,
3841 'type-del=s' => $delete_spec,
3844 foreach my $source (@{$arg_sources}) {
3845 my ( $source_name, $args ) = @{$source}{qw/name contents/};
3847 if ( ref($args) ) {
3848 # $args are modified in place, so no need to munge $arg_sources
3849 local @ARGV = @{$args};
3850 Getopt::Long::GetOptions(%type_arg_specs);
3851 @{$args} = @ARGV;
3853 else {
3854 ( undef, $source->{contents} ) =
3855 Getopt::Long::GetOptionsFromString($args, %type_arg_specs);
3859 $additional_specs{'k|known-types'} = sub {
3860 my ( undef, $value ) = @_;
3862 my @filters = map { @{$_} } values(%App::Ack::mappings);
3864 push @{ $opt->{'filters'} }, @filters;
3867 return \%additional_specs;
3871 sub removed_option {
3872 my ( $option, $explanation ) = @_;
3874 $explanation ||= '';
3875 return sub {
3876 warn "Option '$option' is not valid in ack 2\n$explanation";
3877 exit 1;
3882 sub get_arg_spec {
3883 my ( $opt, $extra_specs ) = @_;
3885 my $dash_a_explanation = <<'EOT';
3886 This is because we now have -k/--known-types which makes it only select files
3887 of known types, rather than any text file (which is the behavior of ack 1.x).
3888 You may have options in a .ackrc, or in the ACKRC_OPTIONS environment variable.
3889 Try using the --dump flag.
3893 return {
3894 1 => sub { $opt->{1} = $opt->{m} = 1 },
3895 'A|after-context=i' => \$opt->{after_context},
3896 'B|before-context=i'
3897 => \$opt->{before_context},
3898 'C|context:i' => sub { shift; my $val = shift; $opt->{before_context} = $opt->{after_context} = ($val || 2) },
3899 'a' => removed_option('-a', $dash_a_explanation),
3900 'all' => removed_option('--all', $dash_a_explanation),
3901 'break!' => \$opt->{break},
3902 c => \$opt->{count},
3903 'color|colour!' => \$opt->{color},
3904 'color-match=s' => \$ENV{ACK_COLOR_MATCH},
3905 'color-filename=s' => \$ENV{ACK_COLOR_FILENAME},
3906 'color-lineno=s' => \$ENV{ACK_COLOR_LINENO},
3907 'column!' => \$opt->{column},
3908 count => \$opt->{count},
3909 'create-ackrc' => sub { print "$_\n" for ( '--ignore-ack-defaults', App::Ack::ConfigDefault::options() ); exit; },
3910 'env!' => sub {
3911 my ( undef, $value ) = @_;
3913 if ( !$value ) {
3914 $opt->{noenv_seen} = 1;
3917 f => \$opt->{f},
3918 'files-from=s' => \$opt->{files_from},
3919 'filter!' => \$App::Ack::is_filter_mode,
3920 flush => \$opt->{flush},
3921 'follow!' => \$opt->{follow},
3922 g => \$opt->{g},
3923 G => removed_option('-G'),
3924 'group!' => sub { shift; $opt->{heading} = $opt->{break} = shift },
3925 'heading!' => \$opt->{heading},
3926 'h|no-filename' => \$opt->{h},
3927 'H|with-filename' => \$opt->{H},
3928 'i|ignore-case' => \$opt->{i},
3929 'ignore-directory|ignore-dir=s' => sub {
3930 my ( undef, $dir ) = @_;
3932 $dir = App::Ack::remove_dir_sep( $dir );
3933 if ( $dir !~ /^(?:is|match):/ ) {
3934 $dir = 'is:' . $dir;
3936 push @{ $opt->{idirs} }, $dir;
3938 'ignore-file=s' => sub {
3939 my ( undef, $file ) = @_;
3940 push @{ $opt->{ifiles} }, $file;
3942 'lines=s' => sub { shift; my $val = shift; push @{$opt->{lines}}, $val },
3943 'l|files-with-matches'
3944 => \$opt->{l},
3945 'L|files-without-matches'
3946 => \$opt->{L},
3947 'm|max-count=i' => \$opt->{m},
3948 'match=s' => \$opt->{regex},
3949 'n|no-recurse' => \$opt->{n},
3950 o => sub { $opt->{output} = '$&' },
3951 'output=s' => \$opt->{output},
3952 'pager:s' => sub {
3953 my ( undef, $value ) = @_;
3955 $opt->{pager} = $value || $ENV{PAGER};
3957 'noignore-directory|noignore-dir=s'
3958 => sub {
3959 my ( undef, $dir ) = @_;
3961 # XXX can you do --noignore-dir=match,...?
3962 $dir = App::Ack::remove_dir_sep( $dir );
3963 if ( $dir !~ /^(?:is|match):/ ) {
3964 $dir = 'is:' . $dir;
3966 if ( $dir !~ /^(?:is|match):/ ) {
3967 Carp::croak("invalid noignore-directory argument: '$dir'");
3970 @{ $opt->{idirs} } = grep {
3971 $_ ne $dir
3972 } @{ $opt->{idirs} };
3974 push @{ $opt->{no_ignore_dirs} }, $dir;
3976 'nopager' => sub { $opt->{pager} = undef },
3977 'passthru' => \$opt->{passthru},
3978 'print0' => \$opt->{print0},
3979 'Q|literal' => \$opt->{Q},
3980 'r|R|recurse' => sub { $opt->{n} = 0 },
3981 's' => \$opt->{dont_report_bad_filenames},
3982 'show-types' => \$opt->{show_types},
3983 'smart-case!' => \$opt->{smart_case},
3984 'sort-files' => \$opt->{sort_files},
3985 'type=s' => sub {
3986 my ( $getopt, $value ) = @_;
3988 my $cb_value = 1;
3989 if ( $value =~ s/^no// ) {
3990 $cb_value = 0;
3993 my $callback = $extra_specs->{ $value . '!' };
3995 if ( $callback ) {
3996 $callback->( $getopt, $cb_value );
3998 else {
3999 Carp::croak( "Unknown type '$value'" );
4002 'u' => removed_option('-u'),
4003 'unrestricted' => removed_option('--unrestricted'),
4004 'v|invert-match' => \$opt->{v},
4005 'w|word-regexp' => \$opt->{w},
4006 'x' => sub { $opt->{files_from} = '-' },
4008 'version' => sub { App::Ack::print_version_statement(); exit; },
4009 'help|?:s' => sub { shift; App::Ack::show_help(@_); exit; },
4010 'help-types' => sub { App::Ack::show_help_types(); exit; },
4011 'man' => sub { App::Ack::show_man(); exit; },
4012 $extra_specs ? %{$extra_specs} : (),
4013 }; # arg_specs
4017 sub process_other {
4018 my ( $opt, $extra_specs, $arg_sources ) = @_;
4020 # Start with default options, minus some annoying ones.
4021 Getopt::Long::Configure('default', 'no_auto_help', 'no_auto_version');
4022 Getopt::Long::Configure(
4023 'bundling',
4024 'no_ignore_case',
4027 my $argv_source;
4028 my $is_help_types_active;
4030 foreach my $source (@{$arg_sources}) {
4031 my ( $source_name, $args ) = @{$source}{qw/name contents/};
4033 if ( $source_name eq 'ARGV' ) {
4034 $argv_source = $args;
4035 last;
4039 if ( $argv_source ) { # This *should* always be true, but you never know...
4040 my @copy = @{$argv_source};
4041 local @ARGV = @copy;
4043 Getopt::Long::Configure('pass_through');
4045 Getopt::Long::GetOptions(
4046 'help-types' => \$is_help_types_active,
4049 Getopt::Long::Configure('no_pass_through');
4052 my $arg_specs = get_arg_spec($opt, $extra_specs);
4054 foreach my $source (@{$arg_sources}) {
4055 my ( $source_name, $args ) = @{$source}{qw/name contents/};
4057 my $args_for_source = $arg_specs;
4059 if ( $source->{project} ) {
4060 my $illegal = sub {
4061 die "Options --output, --pager and --match are forbidden in project .ackrc files.\n";
4064 $args_for_source = { %$args_for_source,
4065 'output=s' => $illegal,
4066 'pager:s' => $illegal,
4067 'match=s' => $illegal,
4071 my $ret;
4072 if ( ref($args) ) {
4073 local @ARGV = @{$args};
4074 $ret = Getopt::Long::GetOptions( %{$args_for_source} );
4075 @{$args} = @ARGV;
4077 else {
4078 ( $ret, $source->{contents} ) =
4079 Getopt::Long::GetOptionsFromString( $args, %{$args_for_source} );
4081 if ( !$ret ) {
4082 if ( !$is_help_types_active ) {
4083 my $where = $source_name eq 'ARGV' ? 'on command line' : "in $source_name";
4084 App::Ack::die( "Invalid option $where" );
4087 if ( $opt->{noenv_seen} ) {
4088 App::Ack::die( "--noenv found in $source_name" );
4092 # XXX We need to check on a -- in the middle of a non-ARGV source
4094 return;
4098 sub should_dump_options {
4099 my ( $sources ) = @_;
4101 foreach my $source (@{$sources}) {
4102 my ( $name, $options ) = @{$source}{qw/name contents/};
4104 if($name eq 'ARGV') {
4105 my $dump;
4106 local @ARGV = @{$options};
4107 Getopt::Long::Configure('default', 'pass_through', 'no_auto_help', 'no_auto_version');
4108 Getopt::Long::GetOptions(
4109 'dump' => \$dump,
4111 @{$options} = @ARGV;
4112 return $dump;
4115 return;
4119 sub explode_sources {
4120 my ( $sources ) = @_;
4122 my @new_sources;
4124 Getopt::Long::Configure('default', 'pass_through', 'no_auto_help', 'no_auto_version');
4126 my %opt;
4127 my $arg_spec = get_arg_spec(\%opt);
4129 my $add_type = sub {
4130 my ( undef, $arg ) = @_;
4132 # XXX refactor?
4133 if ( $arg =~ /(\w+)=/) {
4134 $arg_spec->{$1} = sub {};
4136 else {
4137 ( $arg ) = split /:/, $arg;
4138 $arg_spec->{$arg} = sub {};
4142 my $del_type = sub {
4143 my ( undef, $arg ) = @_;
4145 delete $arg_spec->{$arg};
4148 foreach my $source (@{$sources}) {
4149 my ( $name, $options ) = @{$source}{qw/name contents/};
4150 if ( ref($options) ne 'ARRAY' ) {
4151 $source->{contents} = $options =
4152 [ Text::ParseWords::shellwords($options) ];
4155 for my $j ( 0 .. @{$options}-1 ) {
4156 next unless $options->[$j] =~ /^-/;
4157 my @chunk = ( $options->[$j] );
4158 push @chunk, $options->[$j] while ++$j < @{$options} && $options->[$j] !~ /^-/;
4159 $j--;
4161 my @copy = @chunk;
4162 local @ARGV = @chunk;
4163 Getopt::Long::GetOptions(
4164 'type-add=s' => $add_type,
4165 'type-set=s' => $add_type,
4166 'type-del=s' => $del_type,
4168 Getopt::Long::GetOptions( %{$arg_spec} );
4170 push @new_sources, {
4171 name => $name,
4172 contents => \@copy,
4177 return \@new_sources;
4181 sub compare_opts {
4182 my ( $a, $b ) = @_;
4184 my $first_a = $a->[0];
4185 my $first_b = $b->[0];
4187 $first_a =~ s/^--?//;
4188 $first_b =~ s/^--?//;
4190 return $first_a cmp $first_b;
4194 sub dump_options {
4195 my ( $sources ) = @_;
4197 $sources = explode_sources($sources);
4199 my %opts_by_source;
4200 my @source_names;
4202 foreach my $source (@{$sources}) {
4203 my ( $name, $contents ) = @{$source}{qw/name contents/};
4204 if ( not $opts_by_source{$name} ) {
4205 $opts_by_source{$name} = [];
4206 push @source_names, $name;
4208 push @{$opts_by_source{$name}}, $contents;
4211 foreach my $name (@source_names) {
4212 my $contents = $opts_by_source{$name};
4214 print $name, "\n";
4215 print '=' x length($name), "\n";
4216 print ' ', join(' ', @{$_}), "\n" foreach sort { compare_opts($a, $b) } @{$contents};
4219 return;
4223 sub remove_default_options_if_needed {
4224 my ( $sources ) = @_;
4226 my $default_index;
4228 foreach my $index ( 0 .. $#{$sources} ) {
4229 if ( $sources->[$index]{'name'} eq 'Defaults' ) {
4230 $default_index = $index;
4231 last;
4235 return $sources unless defined $default_index;
4237 my $should_remove = 0;
4239 # Start with default options, minus some annoying ones.
4240 Getopt::Long::Configure('default', 'no_auto_help', 'no_auto_version');
4241 Getopt::Long::Configure(
4242 'no_ignore_case',
4243 'no_auto_abbrev',
4244 'pass_through',
4247 foreach my $index ( $default_index + 1 .. $#{$sources} ) {
4248 my ( $name, $args ) = @{$sources->[$index]}{qw/name contents/};
4250 if (ref($args)) {
4251 local @ARGV = @{$args};
4252 Getopt::Long::GetOptions(
4253 'ignore-ack-defaults' => \$should_remove,
4255 @{$args} = @ARGV;
4257 else {
4258 ( undef, $sources->[$index]{contents} ) = Getopt::Long::GetOptionsFromString($args,
4259 'ignore-ack-defaults' => \$should_remove,
4264 Getopt::Long::Configure('default');
4265 Getopt::Long::Configure('default', 'no_auto_help', 'no_auto_version');
4267 return $sources unless $should_remove;
4269 my @copy = @{$sources};
4270 splice @copy, $default_index, 1;
4271 return \@copy;
4275 sub check_for_mutually_exclusive_options {
4276 my ( $arg_sources ) = @_;
4278 my %mutually_exclusive_with;
4279 my @copy = @{$arg_sources};
4281 for(my $i = 0; $i < @INVALID_COMBINATIONS; $i += 2) {
4282 my ( $lhs, $rhs ) = @INVALID_COMBINATIONS[ $i, $i + 1 ];
4284 foreach my $l_opt ( @{$lhs} ) {
4285 foreach my $r_opt ( @{$rhs} ) {
4286 push @{ $mutually_exclusive_with{ $l_opt } }, $r_opt;
4287 push @{ $mutually_exclusive_with{ $r_opt } }, $l_opt;
4292 while( @copy ) {
4293 my %set_opts;
4295 my $source = shift @copy;
4296 my ( $source_name, $args ) = @{$source}{qw/name contents/};
4297 $args = ref($args) ? [ @{$args} ] : [ Text::ParseWords::shellwords($args) ];
4299 foreach my $opt ( @{$args} ) {
4300 next unless $opt =~ /^[-+]/;
4301 last if $opt eq '--';
4303 if( $opt =~ /^(.*)=/ ) {
4304 $opt = $1;
4306 elsif ( $opt =~ /^(-[^-]).+/ ) {
4307 $opt = $1;
4310 $set_opts{ $opt } = 1;
4312 my $mutex_opts = $mutually_exclusive_with{ $opt };
4314 next unless $mutex_opts;
4316 foreach my $mutex_opt ( @{$mutex_opts} ) {
4317 if($set_opts{ $mutex_opt }) {
4318 die "Options '$mutex_opt' and '$opt' are mutually exclusive\n";
4326 sub process_args {
4327 my $arg_sources = \@_;
4329 my %opt = (
4330 pager => $ENV{ACK_PAGER_COLOR} || $ENV{ACK_PAGER},
4333 check_for_mutually_exclusive_options($arg_sources);
4335 $arg_sources = remove_default_options_if_needed($arg_sources);
4337 if ( should_dump_options($arg_sources) ) {
4338 dump_options($arg_sources);
4339 exit(0);
4342 my $type_specs = process_filetypes(\%opt, $arg_sources);
4343 process_other(\%opt, $type_specs, $arg_sources);
4344 while ( @{$arg_sources} ) {
4345 my $source = shift @{$arg_sources};
4346 my ( $source_name, $args ) = @{$source}{qw/name contents/};
4348 # All of our sources should be transformed into an array ref
4349 if ( ref($args) ) {
4350 if ( $source_name eq 'ARGV' ) {
4351 @ARGV = @{$args};
4353 elsif (@{$args}) {
4354 Carp::croak "source '$source_name' has extra arguments!";
4357 else {
4358 Carp::croak 'The impossible has occurred!';
4361 my $filters = ($opt{filters} ||= []);
4363 # Throw the default filter in if no others are selected.
4364 if ( not grep { !$_->is_inverted() } @{$filters} ) {
4365 push @{$filters}, App::Ack::Filter::Default->new();
4367 return \%opt;
4371 sub retrieve_arg_sources {
4372 my @arg_sources;
4374 my $noenv;
4375 my $ackrc;
4377 Getopt::Long::Configure('default', 'no_auto_help', 'no_auto_version');
4378 Getopt::Long::Configure('pass_through');
4379 Getopt::Long::Configure('no_auto_abbrev');
4381 Getopt::Long::GetOptions(
4382 'noenv' => \$noenv,
4383 'ackrc=s' => \$ackrc,
4386 Getopt::Long::Configure('default', 'no_auto_help', 'no_auto_version');
4388 my @files;
4390 if ( !$noenv ) {
4391 my $finder = App::Ack::ConfigFinder->new;
4392 @files = $finder->find_config_files;
4394 if ( $ackrc ) {
4395 # We explicitly use open so we get a nice error message.
4396 # XXX This is a potential race condition!.
4397 if(open my $fh, '<', $ackrc) {
4398 close $fh;
4400 else {
4401 die "Unable to load ackrc '$ackrc': $!"
4403 push( @files, { path => $ackrc } );
4406 push @arg_sources, {
4407 name => 'Defaults',
4408 contents => [ App::Ack::ConfigDefault::options_clean() ],
4411 foreach my $file ( @files) {
4412 my @lines = App::Ack::ConfigFinder::read_rcfile($file->{path});
4414 if(@lines) {
4415 push @arg_sources, {
4416 name => $file->{path},
4417 contents => \@lines,
4418 project => $file->{project},
4423 if ( $ENV{ACK_OPTIONS} && !$noenv ) {
4424 push @arg_sources, {
4425 name => 'ACK_OPTIONS',
4426 contents => $ENV{ACK_OPTIONS},
4430 push @arg_sources, {
4431 name => 'ARGV',
4432 contents => [ @ARGV ],
4435 return @arg_sources;
4438 1; # End of App::Ack::ConfigLoader
4439 package App::Ack::Filter;
4441 use strict;
4442 use warnings;
4443 use overload
4444 '""' => 'to_string';
4446 use Carp 1.04 ();
4448 my %filter_types;
4451 sub create_filter {
4452 my ( undef, $type, @args ) = @_;
4454 if ( my $package = $filter_types{$type} ) {
4455 return $package->new(@args);
4457 Carp::croak "Unknown filter type '$type'";
4461 sub register_filter {
4462 my ( undef, $type, $package ) = @_;
4464 $filter_types{$type} = $package;
4466 return;
4470 sub invert {
4471 my ( $self ) = @_;
4473 return App::Ack::Filter::Inverse->new( $self );
4477 sub is_inverted {
4478 return 0;
4482 sub to_string {
4483 my ( $self ) = @_;
4485 return '(unimplemented to_string)';
4489 sub inspect {
4490 my ( $self ) = @_;
4492 return ref($self);
4496 package App::Ack::Filter::Extension;
4498 use strict;
4499 use warnings;
4500 BEGIN {
4501 our @ISA = 'App::Ack::Filter';
4505 sub new {
4506 my ( $class, @extensions ) = @_;
4508 my $exts = join('|', map { "\Q$_\E"} @extensions);
4509 my $re = qr/[.](?:$exts)$/i;
4511 return bless {
4512 extensions => \@extensions,
4513 regex => $re,
4514 groupname => 'ExtensionGroup',
4515 }, $class;
4518 sub create_group {
4519 return App::Ack::Filter::ExtensionGroup->new();
4522 sub filter {
4523 my ( $self, $resource ) = @_;
4525 my $re = $self->{'regex'};
4527 return $resource->name =~ /$re/;
4530 sub inspect {
4531 my ( $self ) = @_;
4533 my $re = $self->{'regex'};
4535 return ref($self) . " - $re";
4538 sub to_string {
4539 my ( $self ) = @_;
4541 my $exts = $self->{'extensions'};
4543 return join(' ', map { ".$_" } @{$exts});
4546 BEGIN {
4547 App::Ack::Filter->register_filter(ext => __PACKAGE__);
4551 package App::Ack::Filter::FirstLineMatch;
4553 use strict;
4554 use warnings;
4555 BEGIN {
4556 our @ISA = 'App::Ack::Filter';
4559 sub new {
4560 my ( $class, $re ) = @_;
4562 $re =~ s{^/|/$}{}g; # XXX validate?
4563 $re = qr{$re}i;
4565 return bless {
4566 regex => $re,
4567 }, $class;
4570 # This test reads the first 250 characters of a file, then just uses the
4571 # first line found in that. This prevents reading something like an entire
4572 # .min.js file (which might be only one "line" long) into memory.
4574 sub filter {
4575 my ( $self, $resource ) = @_;
4577 my $re = $self->{'regex'};
4579 my $line = $resource->firstliney;
4581 return $line =~ /$re/;
4584 sub inspect {
4585 my ( $self ) = @_;
4587 my $re = $self->{'regex'};
4589 return ref($self) . " - $re";
4592 sub to_string {
4593 my ( $self ) = @_;
4595 (my $re = $self->{regex}) =~ s{\([^:]*:(.*)\)$}{$1};
4597 return "first line matches /$re/";
4600 BEGIN {
4601 App::Ack::Filter->register_filter(firstlinematch => __PACKAGE__);
4605 package App::Ack::Filter::Is;
4607 use strict;
4608 use warnings;
4609 BEGIN {
4610 our @ISA = 'App::Ack::Filter';
4613 use File::Spec 3.00 ();
4615 sub new {
4616 my ( $class, $filename ) = @_;
4618 return bless {
4619 filename => $filename,
4620 groupname => 'IsGroup',
4621 }, $class;
4624 sub create_group {
4625 return App::Ack::Filter::IsGroup->new();
4628 sub filter {
4629 my ( $self, $resource ) = @_;
4631 my $filename = $self->{'filename'};
4632 my $base = (File::Spec->splitpath($resource->name))[2];
4634 return $base eq $filename;
4637 sub inspect {
4638 my ( $self ) = @_;
4640 my $filename = $self->{'filename'};
4642 return ref($self) . " - $filename";
4645 sub to_string {
4646 my ( $self ) = @_;
4648 my $filename = $self->{'filename'};
4650 return $filename;
4653 BEGIN {
4654 App::Ack::Filter->register_filter(is => __PACKAGE__);
4658 package App::Ack::Filter::Match;
4660 use strict;
4661 use warnings;
4662 BEGIN {
4663 our @ISA = 'App::Ack::Filter';
4666 use File::Spec 3.00;
4668 sub new {
4669 my ( $class, $re ) = @_;
4671 $re =~ s{^/|/$}{}g; # XXX validate?
4672 $re = qr/$re/i;
4674 return bless {
4675 regex => $re,
4676 }, $class;
4679 sub filter {
4680 my ( $self, $resource ) = @_;
4682 my $re = $self->{'regex'};
4683 my $base = (File::Spec->splitpath($resource->name))[2];
4685 return $base =~ /$re/;
4688 sub inspect {
4689 my ( $self ) = @_;
4691 my $re = $self->{'regex'};
4693 print ref($self) . " - $re";
4695 return;
4698 sub to_string {
4699 my ( $self ) = @_;
4701 my $re = $self->{'regex'};
4703 return "filename matches $re";
4706 BEGIN {
4707 App::Ack::Filter->register_filter(match => __PACKAGE__);
4711 package App::Ack::Filter::Default;
4713 use strict;
4714 use warnings;
4715 BEGIN {
4716 our @ISA = 'App::Ack::Filter';
4719 sub new {
4720 my ( $class ) = @_;
4722 return bless {}, $class;
4725 sub filter {
4726 my ( $self, $resource ) = @_;
4728 return -T $resource->name;
4732 package App::Ack::Filter::Inverse;
4734 use strict;
4735 use warnings;
4736 BEGIN {
4737 our @ISA = 'App::Ack::Filter';
4740 sub new {
4741 my ( $class, $filter ) = @_;
4743 return bless {
4744 filter => $filter,
4745 }, $class;
4748 sub filter {
4749 my ( $self, $resource ) = @_;
4751 my $filter = $self->{'filter'};
4752 return !$filter->filter( $resource );
4755 sub invert {
4756 my $self = shift;
4758 return $self->{'filter'};
4761 sub is_inverted {
4762 return 1;
4765 sub inspect {
4766 my ( $self ) = @_;
4768 my $filter = $self->{'filter'};
4770 return "!$filter";
4774 package App::Ack::Filter::Collection;
4776 use strict;
4777 use warnings;
4778 BEGIN {
4779 our @ISA = 'App::Ack::Filter';
4782 sub new {
4783 my ( $class ) = @_;
4785 return bless {
4786 groups => {},
4787 ungrouped => [],
4788 }, $class;
4791 sub filter {
4792 my ( $self, $resource ) = @_;
4794 for my $group (values %{$self->{'groups'}}) {
4795 if ($group->filter($resource)) {
4796 return 1;
4800 for my $filter (@{$self->{'ungrouped'}}) {
4801 if ($filter->filter($resource)) {
4802 return 1;
4806 return 0;
4809 sub add {
4810 my ( $self, $filter ) = @_;
4812 if (exists $filter->{'groupname'}) {
4813 my $group = ($self->{groups}->{$filter->{groupname}} ||= $filter->create_group());
4814 $group->add($filter);
4816 else {
4817 push @{$self->{'ungrouped'}}, $filter;
4820 return;
4823 sub inspect {
4824 my ( $self ) = @_;
4826 return ref($self) . " - $self";
4829 sub to_string {
4830 my ( $self ) = @_;
4832 my $ungrouped = $self->{'ungrouped'};
4834 return join(', ', map { "($_)" } @{$ungrouped});
4838 package App::Ack::Filter::IsGroup;
4840 use strict;
4841 use warnings;
4842 BEGIN {
4843 our @ISA = 'App::Ack::Filter';
4846 use File::Spec 3.00 ();
4848 sub new {
4849 my ( $class ) = @_;
4851 return bless {
4852 data => {},
4853 }, $class;
4856 sub add {
4857 my ( $self, $filter ) = @_;
4859 $self->{data}->{ $filter->{filename} } = 1;
4861 return;
4864 sub filter {
4865 my ( $self, $resource ) = @_;
4867 my $data = $self->{'data'};
4868 my $base = (File::Spec->splitpath($resource->name))[2];
4870 return exists $data->{$base};
4873 sub inspect {
4874 my ( $self ) = @_;
4876 return ref($self) . " - $self";
4879 sub to_string {
4880 my ( $self ) = @_;
4882 return join(' ', keys %{$self->{data}});
4886 package App::Ack::Filter::ExtensionGroup;
4888 use strict;
4889 use warnings;
4890 BEGIN {
4891 our @ISA = 'App::Ack::Filter';
4894 sub new {
4895 my ( $class ) = @_;
4897 return bless {
4898 data => {},
4899 }, $class;
4902 sub add {
4903 my ( $self, $filter ) = @_;
4905 foreach my $ext (@{$filter->{extensions}}) {
4906 $self->{data}->{lc $ext} = 1;
4909 return;
4912 sub filter {
4913 my ( $self, $resource ) = @_;
4915 if ($resource->name =~ /[.]([^.]*)$/) {
4916 return exists $self->{'data'}->{lc $1};
4919 return 0;
4922 sub inspect {
4923 my ( $self ) = @_;
4925 return ref($self) . " - $self";
4928 sub to_string {
4929 my ( $self ) = @_;
4931 return join(' ', map { ".$_" } sort keys %{$self->{data}});
4935 package File::Next;
4937 use strict;
4938 use warnings;
4941 our $VERSION = '1.12';
4945 use File::Spec ();
4947 our $name; # name of the current file
4948 our $dir; # dir of the current file
4950 our %files_defaults;
4951 our %skip_dirs;
4953 BEGIN {
4954 %files_defaults = (
4955 file_filter => undef,
4956 descend_filter => undef,
4957 error_handler => sub { CORE::die @_ },
4958 warning_handler => sub { CORE::warn @_ },
4959 sort_files => undef,
4960 follow_symlinks => 1,
4961 nul_separated => 0,
4963 %skip_dirs = map {($_,1)} (File::Spec->curdir, File::Spec->updir);
4967 sub files {
4968 die _bad_invocation() if @_ && defined($_[0]) && ($_[0] eq __PACKAGE__);
4970 my ($parms,@queue) = _setup( \%files_defaults, @_ );
4971 my $filter = $parms->{file_filter};
4973 return sub {
4974 while (@queue) {
4975 my ($dirname,$file,$fullpath) = splice( @queue, 0, 3 );
4976 if ( -f $fullpath || -p $fullpath || $fullpath =~ m{^/dev/fd} ) {
4977 if ( $filter ) {
4978 local $_ = $file;
4979 local $File::Next::dir = $dirname;
4980 local $File::Next::name = $fullpath;
4981 next if not $filter->();
4983 return wantarray ? ($dirname,$file,$fullpath) : $fullpath;
4985 elsif ( -d _ ) {
4986 unshift( @queue, _candidate_files( $parms, $fullpath ) );
4988 } # while
4990 return;
4991 }; # iterator
4999 sub from_file {
5000 die _bad_invocation() if @_ && defined($_[0]) && ($_[0] eq __PACKAGE__);
5002 my ($parms,@queue) = _setup( \%files_defaults, @_ );
5003 my $err = $parms->{error_handler};
5004 my $warn = $parms->{error_handler};
5006 my $filename = $queue[1];
5008 if ( !defined($filename) ) {
5009 $err->( 'Must pass a filename to from_file()' );
5010 return undef;
5013 my $fh;
5014 if ( $filename eq '-' ) {
5015 $fh = \*STDIN;
5017 else {
5018 if ( !open( $fh, '<', $filename ) ) {
5019 $err->( "Unable to open $filename: $!" );
5020 return undef;
5023 my $filter = $parms->{file_filter};
5025 return sub {
5026 local $/ = $parms->{nul_separated} ? "\x00" : $/;
5027 while ( my $fullpath = <$fh> ) {
5028 chomp $fullpath;
5029 next unless $fullpath =~ /./;
5030 if ( not ( -f $fullpath || -p _ ) ) {
5031 $warn->( "$fullpath: No such file" );
5032 next;
5035 my ($volume,$dirname,$file) = File::Spec->splitpath( $fullpath );
5036 if ( $filter ) {
5037 local $_ = $file;
5038 local $File::Next::dir = $dirname;
5039 local $File::Next::name = $fullpath;
5040 next if not $filter->();
5042 return wantarray ? ($dirname,$file,$fullpath) : $fullpath;
5043 } # while
5044 close $fh;
5046 return;
5047 }; # iterator
5050 sub _bad_invocation {
5051 my $good = (caller(1))[3];
5052 my $bad = $good;
5053 $bad =~ s/(.+)::/$1->/;
5054 return "$good must not be invoked as $bad";
5057 sub sort_standard($$) { return $_[0]->[1] cmp $_[1]->[1] }
5058 sub sort_reverse($$) { return $_[1]->[1] cmp $_[0]->[1] }
5060 sub reslash {
5061 my $path = shift;
5063 my @parts = split( /\//, $path );
5065 return $path if @parts < 2;
5067 return File::Spec->catfile( @parts );
5072 sub _setup {
5073 my $defaults = shift;
5074 my $passed_parms = ref $_[0] eq 'HASH' ? {%{+shift}} : {}; # copy parm hash
5076 my %passed_parms = %{$passed_parms};
5078 my $parms = {};
5079 for my $key ( keys %{$defaults} ) {
5080 $parms->{$key} =
5081 exists $passed_parms{$key}
5082 ? delete $passed_parms{$key}
5083 : $defaults->{$key};
5086 # Any leftover keys are bogus
5087 for my $badkey ( keys %passed_parms ) {
5088 my $sub = (caller(1))[3];
5089 $parms->{error_handler}->( "Invalid option passed to $sub(): $badkey" );
5092 # If it's not a code ref, assume standard sort
5093 if ( $parms->{sort_files} && ( ref($parms->{sort_files}) ne 'CODE' ) ) {
5094 $parms->{sort_files} = \&sort_standard;
5096 my @queue;
5098 for ( @_ ) {
5099 my $start = reslash( $_ );
5100 if (-d $start) {
5101 push @queue, ($start,undef,$start);
5103 else {
5104 push @queue, (undef,$start,$start);
5108 return ($parms,@queue);
5112 sub _candidate_files {
5113 my $parms = shift;
5114 my $dirname = shift;
5116 my $dh;
5117 if ( !opendir $dh, $dirname ) {
5118 $parms->{error_handler}->( "$dirname: $!" );
5119 return;
5122 my @newfiles;
5123 my $descend_filter = $parms->{descend_filter};
5124 my $follow_symlinks = $parms->{follow_symlinks};
5125 my $sort_sub = $parms->{sort_files};
5127 for my $file ( grep { !exists $skip_dirs{$_} } readdir $dh ) {
5128 my $has_stat;
5130 # Only do directory checking if we have a descend_filter
5131 my $fullpath = File::Spec->catdir( $dirname, $file );
5132 if ( !$follow_symlinks ) {
5133 next if -l $fullpath;
5134 $has_stat = 1;
5137 if ( $descend_filter ) {
5138 if ( $has_stat ? (-d _) : (-d $fullpath) ) {
5139 local $File::Next::dir = $fullpath;
5140 local $_ = $file;
5141 next if not $descend_filter->();
5144 if ( $sort_sub ) {
5145 push( @newfiles, [ $dirname, $file, $fullpath ] );
5147 else {
5148 push( @newfiles, $dirname, $file, $fullpath );
5151 closedir $dh;
5153 if ( $sort_sub ) {
5154 return map { @{$_} } sort $sort_sub @newfiles;
5157 return @newfiles;
5161 1; # End of File::Next