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