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