@ 11d698f

170325.2 · d0cd00029c71977f587e362856582ddd42f48e77

Bringing over 2.18 from the ack2 repo

reading declarations

Changes to garage/ack-1.96. All files

garage/ack-1.96

new file mode 100755@@ -0,0 +1,2844 @@+#!/usr/bin/env perl+#+# This file, ack, is generated code.+# Please DO NOT EDIT or send patches for it.+#+# Please take a look at the source from+# https://github.com/petdance/ack+# and submit patches against the individual files+# that build ack.+#++use warnings;+use strict;++our $VERSION = '1.96';+# Check http://betterthangrep.com/ for updates++# These are all our globals.+++MAIN: {+    if ( $App::Ack::VERSION ne $main::VERSION ) {+        App::Ack::die( "Program/library version mismatch\n\t$0 is $main::VERSION\n\t$INC{'App/Ack.pm'} is $App::Ack::VERSION" );+    }++    # Do preliminary arg checking;+    my $env_is_usable = 1;+    for ( @ARGV ) {+        last if ( $_ eq '--' );++        # Priorities! Get the --thpppt and --bar checking out of the way.+        /^--th[pt]+t+$/ && App::Ack::_thpppt($_);+        /^--bar$/ && App::Ack::_bar();++        # See if we want to ignore the environment. (Don't tell Al Gore.)+        if ( /^--(no)?env$/ ) {+            $env_is_usable = defined $1 ? 0 : 1;+        }+    }+    if ( $env_is_usable ) {+        unshift( @ARGV, App::Ack::read_ackrc() );+    }+    else {+        my @keys = ( 'ACKRC', grep { /^ACK_/ } keys %ENV );+        delete @ENV{@keys};+    }+    App::Ack::load_colors();++    if ( exists $ENV{ACK_SWITCHES} ) {+        App::Ack::warn( 'ACK_SWITCHES is no longer supported.  Use ACK_OPTIONS.' );+    }++    if ( !@ARGV ) {+        App::Ack::show_help();+        exit 1;+    }++    main();+}++sub main {+    my $opt = App::Ack::get_command_line_options();++    $| = 1 if $opt->{flush}; # Unbuffer the output if flush mode++    if ( App::Ack::input_from_pipe() ) {+        # We're going into filter mode+        for ( qw( f g l ) ) {+            $opt->{$_} and App::Ack::die( "Can't use -$_ when acting as a filter." );+        }+        $opt->{show_filename} = 0;+        $opt->{regex} = App::Ack::build_regex( defined $opt->{regex} ? $opt->{regex} : shift @ARGV, $opt );+        if ( my $nargs = @ARGV ) {+            my $s = $nargs == 1 ? '' : 's';+            App::Ack::warn( "Ignoring $nargs argument$s on the command-line while acting as a filter." );+        }++        my $res = App::Ack::Resource::Basic->new( '-' );+        my $nmatches;+        if ( $opt->{count} ) {+            $nmatches = App::Ack::search_and_list( $res, $opt );+        }+        else {+            # normal searching+            $nmatches = App::Ack::search_resource( $res, $opt );+        }+        $res->close();+        App::Ack::exit_from_ack( $nmatches );+    }++    my $file_matching = $opt->{f} || $opt->{lines};+    if ( $file_matching ) {+        App::Ack::die( "Can't specify both a regex ($opt->{regex}) and use one of --line, -f or -g." ) if $opt->{regex};+    }+    else {+        $opt->{regex} = App::Ack::build_regex( defined $opt->{regex} ? $opt->{regex} : shift @ARGV, $opt );+    }++    # check that all regexes do compile fine+    App::Ack::check_regex( $_ ) for ( $opt->{regex}, $opt->{G} );++    my $what = App::Ack::get_starting_points( \@ARGV, $opt );+    my $iter = App::Ack::get_iterator( $what, $opt );+    App::Ack::filetype_setup();++    my $nmatches = 0;++    App::Ack::set_up_pager( $opt->{pager} ) if defined $opt->{pager};+    if ( $opt->{f} ) {+        $nmatches = App::Ack::print_files( $iter, $opt );+    }+    elsif ( $opt->{l} || $opt->{count} ) {+        $nmatches = App::Ack::print_files_with_matches( $iter, $opt );+    }+    else {+        $nmatches = App::Ack::print_matches( $iter, $opt );+    }+    close $App::Ack::fh;+    App::Ack::exit_from_ack( $nmatches );+}++=head1 NAME++ack - grep-like text finder++=head1 SYNOPSIS++    ack [options] PATTERN [FILE...]+    ack -f [options] [DIRECTORY...]++=head1 DESCRIPTION++Ack is designed as a replacement for 99% of the uses of F<grep>.++Ack searches the named input FILEs (or standard input if no files are+named, or the file name - is given) for lines containing a match to the+given PATTERN.  By default, ack prints the matching lines.++Ack can also list files that would be searched, without actually searching+them, to let you take advantage of ack's file-type filtering capabilities.++=head1 FILE SELECTION++I<ack> is intelligent about the files it searches.  It knows about+certain file types, based on both the extension on the file and,+in some cases, the contents of the file.  These selections can be+made with the B<--type> option.++With no file selections, I<ack> only searches files of types that+it recognizes.  If you have a file called F<foo.wango>, and I<ack>+doesn't know what a .wango file is, I<ack> won't search it.++The B<-a> option tells I<ack> to select all files, regardless of+type.++Some files will never be selected by I<ack>, even with B<-a>,+including:++=over 4++=item * Backup files: Files matching F<#*#> or ending with F<~>.++=item * Coredumps: Files matching F<core.\d+>++=back++However, I<ack> always searches the files given on the command line,+no matter what type. Furthermore, by specifying the B<-u> option all+files will be searched.++=head1 DIRECTORY SELECTION++I<ack> descends through the directory tree of the starting directories+specified.  However, it will ignore the shadow directories used by+many version control systems, and the build directories used by the+Perl MakeMaker system.  You may add or remove a directory from this+list with the B<--[no]ignore-dir> option. The option may be repeated+to add/remove multiple directories from the ignore list.++For a complete list of directories that do not get searched, run+F<ack --help>.++=head1 WHEN TO USE GREP++I<ack> trumps I<grep> as an everyday tool 99% of the time, but don't+throw I<grep> away, because there are times you'll still need it.++E.g., searching through huge files looking for regexes that can be+expressed with I<grep> syntax should be quicker with I<grep>.++If your script or parent program uses I<grep> C<--quiet> or+C<--silent> or needs exit 2 on IO error, use I<grep>.++=head1 OPTIONS++=over 4++=item B<-a>, B<--all>++Operate on all files, regardless of type (but still skip directories+like F<blib>, F<CVS>, etc.)++=item B<-A I<NUM>>, B<--after-context=I<NUM>>++Print I<NUM> lines of trailing context after matching lines.++=item B<-B I<NUM>>, B<--before-context=I<NUM>>++Print I<NUM> lines of leading context before matching lines.++=item B<-C [I<NUM>]>, B<--context[=I<NUM>]>++Print I<NUM> lines (default 2) of context around matching lines.++=item B<-c>, B<--count>++Suppress normal output; instead print a count of matching lines for+each input file.  If B<-l> is in effect, it will only show the+number of lines for each file that has lines matching.  Without+B<-l>, some line counts may be zeroes.++If combined with B<-h> (B<--no-filename>) ack outputs only one total count.++=item B<--color>, B<--nocolor>++B<--color> highlights the matching text.  B<--nocolor> supresses+the color.  This is on by default unless the output is redirected.++On Windows, this option is off by default unless the+L<Win32::Console::ANSI> module is installed or the C<ACK_PAGER_COLOR>+environment variable is used.++=item B<--color-filename=I<color>>++Sets the color to be used for filenames.++=item B<--color-match=I<color>>++Sets the color to be used for matches.++=item B<--color-lineno=I<color>>++Sets the color to be used for line numbers.++=item B<--column>++Show the column number of the first match.  This is helpful for editors+that can place your cursor at a given position.++=item B<--env>, B<--noenv>++B<--noenv> disables all environment processing. No F<.ackrc> is read+and all environment variables are ignored. By default, F<ack> considers+F<.ackrc> and settings in the environment.++=item B<--flush>++B<--flush> flushes output immediately.  This is off by default+unless ack is running interactively (when output goes to a pipe+or file).++=item B<-f>++Only print the files that would be searched, without actually doing+any searching.  PATTERN must not be specified, or it will be taken as+a path to search.++=item B<--follow>, B<--nofollow>++Follow or don't follow symlinks, other than whatever starting files+or directories were specified on the command line.++This is off by default.++=item B<-G I<REGEX>>++Only paths matching I<REGEX> are included in the search.  The entire+path and filename are matched against I<REGEX>, and I<REGEX> is a+Perl regular expression, not a shell glob.++The options B<-i>, B<-w>, B<-v>, and B<-Q> do not apply to this I<REGEX>.++=item B<-g I<REGEX>>++Print files where the relative path + filename matches I<REGEX>. This option is+a convenience shortcut for B<-f> B<-G I<REGEX>>.++The options B<-i>, B<-w>, B<-v>, and B<-Q> do not apply to this I<REGEX>.++=item B<--group>, B<--nogroup>++B<--group> groups matches by file name with.  This is the default when+used interactively.++B<--nogroup> prints one result per line, like grep.  This is the default+when output is redirected.++=item B<-H>, B<--with-filename>++Print the filename for each match.++=item B<-h>, B<--no-filename>++Suppress the prefixing of filenames on output when multiple files are+searched.++=item B<--help>++Print a short help statement.++=item B<-i>, B<--ignore-case>++Ignore case in the search strings.++This applies only to the PATTERN, not to the regexes given for the B<-g>+and B<-G> options.++=item B<--[no]ignore-dir=I<DIRNAME>>++Ignore directory (as CVS, .svn, etc are ignored). May be used multiple times+to ignore multiple directories. For example, mason users may wish to include+B<--ignore-dir=data>. The B<--noignore-dir> option allows users to search+directories which would normally be ignored (perhaps to research the contents+of F<.svn/props> directories).++The I<DIRNAME> must always be a simple directory name. Nested directories like+F<foo/bar> are NOT supported. You would need to specify B<--ignore-dir=foo> and+then no files from any foo directory are taken into account by ack unless given+explicitly on the command line.++=item B<--line=I<NUM>>++Only print line I<NUM> of each file. Multiple lines can be given with multiple+B<--line> options or as a comma separated list (B<--line=3,5,7>). B<--line=4-7>+also works. The lines are always output in ascending order, no matter the+order given on the command line.++=item B<-l>, B<--files-with-matches>++Only print the filenames of matching files, instead of the matching text.++=item B<-L>, B<--files-without-matches>++Only print the filenames of files that do I<NOT> match. This is equivalent+to specifying B<-l> and B<-v>.++=item B<--match I<REGEX>>++Specify the I<REGEX> explicitly. This is helpful if you don't want to put the+regex as your first argument, e.g. when executing multiple searches over the+same set of files.++    # search for foo and bar in given files+    ack file1 t/file* --match foo+    ack file1 t/file* --match bar++=item B<-m=I<NUM>>, B<--max-count=I<NUM>>++Stop reading a file after I<NUM> matches.++=item B<--man>++Print this manual page.++=item B<-n>, B<--no-recurse>++No descending into subdirectories.++=item B<-o>++Show only the part of each line matching PATTERN (turns off text+highlighting)++=item B<--output=I<expr>>++Output the evaluation of I<expr> for each line (turns off text+highlighting)++=item B<--pager=I<program>>++Direct ack's output through I<program>.  This can also be specified+via the C<ACK_PAGER> and C<ACK_PAGER_COLOR> environment variables.++Using --pager does not suppress grouping and coloring like piping+output on the command-line does.++=item B<--passthru>++Prints all lines, whether or not they match the expression.  Highlighting+will still work, though, so it can be used to highlight matches while+still seeing the entire file, as in:++    # Watch a log file, and highlight a certain IP address+    $ tail -f ~/access.log | ack --passthru 123.45.67.89++=item B<--print0>++Only works in conjunction with -f, -g, -l or -c (filename output). The filenames+are output separated with a null byte instead of the usual newline. This is+helpful when dealing with filenames that contain whitespace, e.g.++    # remove all files of type html+    ack -f --html --print0 | xargs -0 rm -f++=item B<-Q>, B<--literal>++Quote all metacharacters in PATTERN, it is treated as a literal.++This applies only to the PATTERN, not to the regexes given for the B<-g>+and B<-G> options.++=item B<-r>, B<-R>, B<--recurse>++Recurse into sub-directories. This is the default and just here for+compatibility with grep. You can also use it for turning B<--no-recurse> off.++=item B<--smart-case>, B<--no-smart-case>++Ignore case in the search strings if PATTERN contains no uppercase+characters. This is similar to C<smartcase> in vim. This option is+off by default.++B<-i> always overrides this option.++This applies only to the PATTERN, not to the regexes given for the+B<-g> and B<-G> options.++=item B<--sort-files>++Sorts the found files lexically.  Use this if you want your file+listings to be deterministic between runs of I<ack>.++=item B<--show-types>++Outputs the filetypes that ack associates with each file.++Works with B<-f> and B<-g> options.++=item B<--thpppt>++Display the all-important Bill The Cat logo.  Note that the exact+spelling of B<--thpppppt> is not important.  It's checked against+a regular expression.++=item B<--bar>++Check with the admiral for traps.++=item B<--type=TYPE>, B<--type=noTYPE>++Specify the types of files to include or exclude from a search.+TYPE is a filetype, like I<perl> or I<xml>.  B<--type=perl> can+also be specified as B<--perl>, and B<--type=noperl> can be done+as B<--noperl>.++If a file is of both type "foo" and "bar", specifying --foo and+--nobar will exclude the file, because an exclusion takes precedence+over an inclusion.++Type specifications can be repeated and are ORed together.++See I<ack --help=types> for a list of valid types.++=item B<--type-add I<TYPE>=I<.EXTENSION>[,I<.EXT2>[,...]]>++Files with the given EXTENSION(s) are recognized as being of (the+existing) type TYPE. See also L</"Defining your own types">.+++=item B<--type-set I<TYPE>=I<.EXTENSION>[,I<.EXT2>[,...]]>++Files with the given EXTENSION(s) are recognized as being of type+TYPE. This replaces an existing definition for type TYPE.  See also+L</"Defining your own types">.++=item B<-u>, B<--unrestricted>++All files and directories (including blib/, core.*, ...) are searched,+nothing is skipped. When both B<-u> and B<--ignore-dir> are used, the+B<--ignore-dir> option has no effect.++=item B<-v>, B<--invert-match>++Invert match: select non-matching lines++This applies only to the PATTERN, not to the regexes given for the B<-g>+and B<-G> options.++=item B<--version>++Display version and copyright information.++=item B<-w>, B<--word-regexp>++Force PATTERN to match only whole words.  The PATTERN is wrapped with+C<\b> metacharacters.++This applies only to the PATTERN, not to the regexes given for the B<-g>+and B<-G> options.++=item B<-1>++Stops after reporting first match of any kind.  This is different+from B<--max-count=1> or B<-m1>, where only one match per file is+shown.  Also, B<-1> works with B<-f> and B<-g>, where B<-m> does+not.++=back++=head1 THE .ackrc FILE++The F<.ackrc> file contains command-line options that are prepended+to the command line before processing.  Multiple options may live+on multiple lines.  Lines beginning with a # are ignored.  A F<.ackrc>+might look like this:++    # Always sort the files+    --sort-files++    # Always color, even if piping to a another program+    --color++    # Use "less -r" as my pager+    --pager=less -r++Note that arguments with spaces in them do not need to be quoted,+as they are not interpreted by the shell. Basically, each I<line>+in the F<.ackrc> file is interpreted as one element of C<@ARGV>.++F<ack> looks in your home directory for the F<.ackrc>.  You can+specify another location with the F<ACKRC> variable, below.++If B<--noenv> is specified on the command line, the F<.ackrc> file+is ignored.++=head1 Defining your own types++ack allows you to define your own types in addition to the predefined+types. This is done with command line options that are best put into+an F<.ackrc> file - then you do not have to define your types over and+over again. In the following examples the options will always be shown+on one command line so that they can be easily copy & pasted.++I<ack --perl foo> searches for foo in all perl files. I<ack --help=types>+tells you, that perl files are files ending+in .pl, .pm, .pod or .t. So what if you would like to include .xs+files as well when searching for --perl files? I<ack --type-add perl=.xs --perl foo>+does this for you. B<--type-add> appends+additional extensions to an existing type.++If you want to define a new type, or completely redefine an existing+type, then use B<--type-set>. I<ack --type-set+eiffel=.e,.eiffel> defines the type I<eiffel> to include files with+the extensions .e or .eiffel. So to search for all eiffel files+containing the word Bertrand use I<ack --type-set eiffel=.e,.eiffel --eiffel Bertrand>.+As usual, you can also write B<--type=eiffel>+instead of B<--eiffel>. Negation also works, so B<--noeiffel> excludes+all eiffel files from a search. Redefining also works: I<ack --type-set cc=.c,.h>+and I<.xs> files no longer belong to the type I<cc>.++When defining your own types in the F<.ackrc> file you have to use+the following:++  --type-set=eiffel=.e,.eiffel++or writing on separate lines++  --type-set+  eiffel=.e,.eiffel++The following does B<NOT> work in the F<.ackrc> file:++  --type-set eiffel=.e,.eiffel+++In order to see all currently defined types, use I<--help types>, e.g.+I<ack --type-set backup=.bak --type-add perl=.perl --help types>++Restrictions:++=over 4++=item++The types 'skipped', 'make', 'binary' and 'text' are considered "builtin" and+cannot be altered.++=item++The shebang line recognition of the types 'perl', 'ruby', 'php', 'python',+'shell' and 'xml' cannot be redefined by I<--type-set>, it is always+active. However, the shebang line is only examined for files where the+extension is not recognised. Therefore it is possible to say+I<ack --type-set perl=.perl --type-set foo=.pl,.pm,.pod,.t --perl --nofoo> and+only find your shiny new I<.perl> files (and all files with unrecognized extension+and perl on the shebang line).++=back++=head1 ENVIRONMENT VARIABLES++For commonly-used ack options, environment variables can make life much easier.+These variables are ignored if B<--noenv> is specified on the command line.++=over 4++=item ACKRC++Specifies the location of the F<.ackrc> file.  If this file doesn't+exist, F<ack> looks in the default location.++=item ACK_OPTIONS++This variable specifies default options to be placed in front of+any explicit options on the command line.++=item ACK_COLOR_FILENAME++Specifies the color of the filename when it's printed in B<--group>+mode.  By default, it's "bold green".++The recognized attributes are clear, reset, dark, bold, underline,+underscore, blink, reverse, concealed black, red, green, yellow,+blue, magenta, on_black, on_red, on_green, on_yellow, on_blue,+on_magenta, on_cyan, and on_white.  Case is not significant.+Underline and underscore are equivalent, as are clear and reset.+The color alone sets the foreground color, and on_color sets the+background color.++This option can also be set with B<--color-filename>.++=item ACK_COLOR_MATCH++Specifies the color of the matching text when printed in B<--color>+mode.  By default, it's "black on_yellow".++This option can also be set with B<--color-match>.++See B<ACK_COLOR_FILENAME> for the color specifications.++=item ACK_COLOR_LINENO++Specifies the color of the line number when printed in B<--color>+mode.  By default, it's "bold yellow".++This option can also be set with B<--color-lineno>.++See B<ACK_COLOR_FILENAME> for the color specifications.++=item ACK_PAGER++Specifies a pager program, such as C<more>, C<less> or C<most>, to which+ack will send its output.++Using C<ACK_PAGER> does not suppress grouping and coloring like+piping output on the command-line does, except that on Windows+ack will assume that C<ACK_PAGER> does not support color.++C<ACK_PAGER_COLOR> overrides C<ACK_PAGER> if both are specified.++=item ACK_PAGER_COLOR++Specifies a pager program that understands ANSI color sequences.+Using C<ACK_PAGER_COLOR> does not suppress grouping and coloring+like piping output on the command-line does.++If you are not on Windows, you never need to use C<ACK_PAGER_COLOR>.++=back++=head1 ACK & OTHER TOOLS++=head2 Vim integration++F<ack> integrates easily with the Vim text editor. Set this in your+F<.vimrc> to use F<ack> instead of F<grep>:++    set grepprg=ack\ -a++That examples uses C<-a> to search through all files, but you may+use other default flags. Now you can search with F<ack> and easily+step through the results in Vim:++  :grep Dumper perllib++=head2 Emacs integration++Phil Jackson put together an F<ack.el> extension that "provides a+simple compilation mode ... has the ability to guess what files you+want to search for based on the major-mode."++L<http://www.shellarchive.co.uk/content/emacs.html>++=head2 TextMate integration++Pedro Melo is a TextMate user who writes "I spend my day mostly+inside TextMate, and the built-in find-in-project sucks with large+projects.  So I hacked a TextMate command that was using find ++grep to use ack.  The result is the Search in Project with ack, and+you can find it here:+L<http://www.simplicidade.org/notes/archives/2008/03/search_in_proje.html>"++=head2 Shell and Return Code++For greater compatibility with I<grep>, I<ack> in normal use returns+shell return or exit code of 0 only if something is found and 1 if+no match is found.++(Shell exit code 1 is C<$?=256> in perl with C<system> or backticks.)++The I<grep> code 2 for errors is not used.++If C<-f> or C<-g> are specified, then 0 is returned if at least one+file is found.  If no files are found, then 1 is returned.++=cut++=head1 DEBUGGING ACK PROBLEMS++If ack gives you output you're not expecting, start with a few simple steps.++=head2 Use B<--noenv>++Your environment variables and F<.ackrc> may be doing things you're+not expecting, or forgotten you specified.  Use B<--noenv> to ignore+your environment and F<.ackrc>.++=head2 Use B<-f> to see what files you're scanning++The reason I created B<-f> in the first place was as a debugging+tool.  If ack is not finding matches you think it should find, run+F<ack -f> to see what files are being checked.++=head1 TIPS++=head2 Use the F<.ackrc> file.++The F<.ackrc> is the place to put all your options you use most of+the time but don't want to remember.  Put all your --type-add and+--type-set definitions in it.  If you like --smart-case, set it+there, too.  I also set --sort-files there.++=head2 Use F<-f> for working with big codesets++Ack does more than search files.  C<ack -f --perl> will create a+list of all the Perl files in a tree, ideal for sending into F<xargs>.+For example:++    # Change all "this" to "that" in all Perl files in a tree.+    ack -f --perl | xargs perl -p -i -e's/this/that/g'++or if you prefer:++    perl -p -i -e's/this/that/g' $(ack -f --perl)++=head2 Use F<-Q> when in doubt about metacharacters++If you're searching for something with a regular expression+metacharacter, most often a period in a filename or IP address, add+the -Q to avoid false positives without all the backslashing.  See+the following example for more...++=head2 Use ack to watch log files++Here's one I used the other day to find trouble spots for a website+visitor.  The user had a problem loading F<troublesome.gif>, so I+took the access log and scanned it with ack twice.++    ack -Q aa.bb.cc.dd /path/to/access.log | ack -Q -B5 troublesome.gif++The first ack finds only the lines in the Apache log for the given+IP.  The second finds the match on my troublesome GIF, and shows+the previous five lines from the log in each case.++=head2 Share your knowledge++Join the ack-users mailing list.  Send me your tips and I may add+them here.++=head1 FAQ++=head2 Why isn't ack finding a match in (some file)?++Probably because it's of a type that ack doesn't recognize.  ack's+searching behavior is driven by filetype.  B<If ack doesn't know+what kind of file it is, ack ignores the file.>++Use the C<-f> switch to see a list of files that ack will search+for you.++If you want ack to search files that it doesn't recognize, use the+C<-a> switch.++If you want ack to search every file, even ones that it always+ignores like coredumps and backup files, use the C<-u> switch.++=head2 Why does ack ignore unknown files by default?++ack is designed by a programmer, for programmers, for searching+large trees of code.  Most codebases have a lot files in them which+aren't source files (like compiled object files, source control+metadata, etc), and grep wastes a lot of time searching through all+of those as well and returning matches from those files.++That's why ack's behavior of not searching things it doesn't recognize+is one of its greatest strengths: the speed you get from only+searching the things that you want to be looking at.++=head2 Wouldn't it be great if F<ack> did search & replace?++No, ack will always be read-only.  Perl has a perfectly good way+to do search & replace in files, using the C<-i>, C<-p> and C<-n>+switches.++You can certainly use ack to select your files to update.  For+example, to change all "foo" to "bar" in all PHP files, you can do+this from the Unix shell:++    $ perl -i -p -e's/foo/bar/g' $(ack -f --php)++=head2 Can you make ack recognize F<.xyz> files?++That's an enhancement.  Please see the section in the manual about+enhancements.++=head2 There's already a program/package called ack.++Yes, I know.++=head2 Why is it called ack if it's called ack-grep?++The name of the program is "ack".  Some packagers have called it+"ack-grep" when creating packages because there's already a package+out there called "ack" that has nothing to do with this ack.++I suggest you make a symlink named F<ack> that points to F<ack-grep>+because one of the crucial benefits of ack is having a name that's+so short and simple to type.++To do that, run this with F<sudo> or as root:++   ln -s /usr/bin/ack-grep /usr/bin/ack++=head2 What does F<ack> mean?++Nothing.  I wanted a name that was easy to type and that you could+pronounce as a single syllable.++=head2 Can I do multi-line regexes?++No, ack does not support regexes that match multiple lines.  Doing+so would require reading in the entire file at a time.++If you want to see lines near your match, use the C<--A>, C<--B>+and C<--C> switches for displaying context.++=head1 AUTHOR++Andy Lester, C<< <andy at petdance.com> >>++=head1 BUGS++Please report any bugs or feature requests to the issues list at+Github: L<https://github.com/petdance/ack/issues>++=head1 ENHANCEMENTS++All enhancement requests MUST first be posted to the ack-users+mailing list at L<http://groups.google.com/group/ack-users>.  I+will not consider a request without it first getting seen by other+ack users.  This includes requests for new filetypes.++There is a list of enhancements I want to make to F<ack> in the ack+issues list at Github: L<https://github.com/petdance/ack/issues>++Patches are always welcome, but patches with tests get the most+attention.++=head1 SUPPORT++Support for and information about F<ack> can be found at:++=over 4++=item * The ack homepage++L<http://betterthangrep.com/>++=item * The ack-users mailing list++L<http://groups.google.com/group/ack-users>++=item * The ack issues list at Github++L<https://github.com/petdance/ack/issues>++=item * AnnoCPAN: Annotated CPAN documentation++L<http://annocpan.org/dist/ack>++=item * CPAN Ratings++L<http://cpanratings.perl.org/d/ack>++=item * Search CPAN++L<http://search.cpan.org/dist/ack>++=item * Git source repository++L<https://github.com/petdance/ack>++=back++=head1 ACKNOWLEDGEMENTS++How appropriate to have I<ack>nowledgements!++Thanks to everyone who has contributed to ack in any way, including+Shlomi Fish,+Karen Etheridge,+Olivier Mengue,+Matthew Wild,+Scott Kyle,+Nick Hooey,+Bo Borgerson,+Mark Szymanski,+Marq Schneider,+Packy Anderson,+JR Boyens,+Dan Sully,+Ryan Niebur,+Kent Fredric,+Mike Morearty,+Ingmar Vanhassel,+Eric Van Dewoestine,+Sitaram Chamarty,+Adam James,+Richard Carlsson,+Pedro Melo,+AJ Schuster,+Phil Jackson,+Michael Schwern,+Jan Dubois,+Christopher J. Madsen,+Matthew Wickline,+David Dyck,+Jason Porritt,+Jjgod Jiang,+Thomas Klausner,+Uri Guttman,+Peter Lewis,+Kevin Riggle,+Ori Avtalion,+Torsten Blix,+Nigel Metheringham,+GE<aacute>bor SzabE<oacute>,+Tod Hagan,+Michael Hendricks,+E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason,+Piers Cawley,+Stephen Steneker,+Elias Lutfallah,+Mark Leighton Fisher,+Matt Diephouse,+Christian Jaeger,+Bill Sully,+Bill Ricker,+David Golden,+Nilson Santos F. Jr,+Elliot Shank,+Merijn Broeren,+Uwe Voelker,+Rick Scott,+Ask BjE<oslash>rn Hansen,+Jerry Gay,+Will Coleda,+Mike O'Regan,+Slaven ReziE<0x107>,+Mark Stosberg,+David Alan Pisoni,+Adriano Ferreira,+James Keenan,+Leland Johnson,+Ricardo Signes+and Pete Krawczyk.++=head1 COPYRIGHT & LICENSE++Copyright 2005-2012 Andy Lester.++This program is free software; you can redistribute it and/or modify+it under the terms of the Artistic License v2.0.++=cut+package File::Next;++use strict;+use warnings;+++our $VERSION = '1.06';++++use File::Spec ();+++our $name; # name of the current file+our $dir;  # dir of the current file++our %files_defaults;+our %skip_dirs;++BEGIN {+    %files_defaults = (+        file_filter     => undef,+        descend_filter  => undef,+        error_handler   => sub { CORE::die @_ },+        sort_files      => undef,+        follow_symlinks => 1,+    );+    %skip_dirs = map {($_,1)} (File::Spec->curdir, File::Spec->updir);+}+++sub files {+    ($_[0] eq __PACKAGE__) && die 'File::Next::files must not be invoked as File::Next->files';++    my ($parms,@queue) = _setup( \%files_defaults, @_ );+    my $filter = $parms->{file_filter};++    return sub {+        while (@queue) {+            my ($dir,$file,$fullpath) = splice( @queue, 0, 3 );+            if ( -f $fullpath ) {+                if ( $filter ) {+                    local $_ = $file;+                    local $File::Next::dir = $dir;+                    local $File::Next::name = $fullpath;+                    next if not $filter->();+                }+                return wantarray ? ($dir,$file,$fullpath) : $fullpath;+            }+            elsif ( -d _ ) {+                unshift( @queue, _candidate_files( $parms, $fullpath ) );+            }+        } # while++        return;+    }; # iterator+}++++++++sub sort_standard($$)   { return $_[0]->[1] cmp $_[1]->[1] }+sub sort_reverse($$)    { return $_[1]->[1] cmp $_[0]->[1] }++sub reslash {+    my $path = shift;++    my @parts = split( /\//, $path );++    return $path if @parts < 2;++    return File::Spec->catfile( @parts );+}++++sub _setup {+    my $defaults = shift;+    my $passed_parms = ref $_[0] eq 'HASH' ? {%{+shift}} : {}; # copy parm hash++    my %passed_parms = %{$passed_parms};++    my $parms = {};+    for my $key ( keys %{$defaults} ) {+        $parms->{$key} =+            exists $passed_parms{$key}+                ? delete $passed_parms{$key}+                : $defaults->{$key};+    }++    # Any leftover keys are bogus+    for my $badkey ( keys %passed_parms ) {+        my $sub = (caller(1))[3];+        $parms->{error_handler}->( "Invalid option passed to $sub(): $badkey" );+    }++    # If it's not a code ref, assume standard sort+    if ( $parms->{sort_files} && ( ref($parms->{sort_files}) ne 'CODE' ) ) {+        $parms->{sort_files} = \&sort_standard;+    }+    my @queue;++    for ( @_ ) {+        my $start = reslash( $_ );+        if (-d $start) {+            push @queue, ($start,undef,$start);+        }+        else {+            push @queue, (undef,$start,$start);+        }+    }++    return ($parms,@queue);+}+++sub _candidate_files {+    my $parms = shift;+    my $dir = shift;++    my $dh;+    if ( !opendir $dh, $dir ) {+        $parms->{error_handler}->( "$dir: $!" );+        return;+    }++    my @newfiles;+    my $descend_filter = $parms->{descend_filter};+    my $follow_symlinks = $parms->{follow_symlinks};+    my $sort_sub = $parms->{sort_files};++    for my $file ( grep { !exists $skip_dirs{$_} } readdir $dh ) {+        my $has_stat;++        # Only do directory checking if we have a descend_filter+        my $fullpath = File::Spec->catdir( $dir, $file );+        if ( !$follow_symlinks ) {+            next if -l $fullpath;+            $has_stat = 1;+        }++        if ( $descend_filter ) {+            if ( $has_stat ? (-d _) : (-d $fullpath) ) {+                local $File::Next::dir = $fullpath;+                local $_ = $file;+                next if not $descend_filter->();+            }+        }+        if ( $sort_sub ) {+            push( @newfiles, [ $dir, $file, $fullpath ] );+        }+        else {+            push( @newfiles, $dir, $file, $fullpath );+        }+    }+    closedir $dh;++    if ( $sort_sub ) {+        return map { @{$_} } sort $sort_sub @newfiles;+    }++    return @newfiles;+}+++1; # End of File::Next+package App::Ack;++use warnings;+use strict;+++++our $VERSION;+our $COPYRIGHT;+BEGIN {+    $VERSION = '1.96';+    $COPYRIGHT = 'Copyright 2005-2011 Andy Lester.';+}++our $fh;++BEGIN {+    $fh = *STDOUT;+}+++our %types;+our %type_wanted;+our %mappings;+our %ignore_dirs;++our $input_from_pipe;+our $output_to_pipe;++our $dir_sep_chars;+our $is_cygwin;+our $is_windows;++use File::Spec ();+use File::Glob ':glob';+use Getopt::Long ();++BEGIN {+    %ignore_dirs = (+        '.bzr'              => 'Bazaar',+        '.cdv'              => 'Codeville',+        '~.dep'             => 'Interface Builder',+        '~.dot'             => 'Interface Builder',+        '~.nib'             => 'Interface Builder',+        '~.plst'            => 'Interface Builder',+        '.git'              => 'Git',+        '.hg'               => 'Mercurial',+        '.pc'               => 'quilt',+        '.svn'              => 'Subversion',+        _MTN                => 'Monotone',+        blib                => 'Perl module building',+        CVS                 => 'CVS',+        RCS                 => 'RCS',+        SCCS                => 'SCCS',+        _darcs              => 'darcs',+        _sgbak              => 'Vault/Fortress',+        'autom4te.cache'    => 'autoconf',+        'cover_db'          => 'Devel::Cover',+        _build              => 'Module::Build',+    );++    %mappings = (+        actionscript => [qw( as mxml )],+        ada         => [qw( ada adb ads )],+        asm         => [qw( asm s )],+        batch       => [qw( bat cmd )],+        binary      => q{Binary files, as defined by Perl's -B op (default: off)},+        cc          => [qw( c h xs )],+        cfmx        => [qw( cfc cfm cfml )],+        clojure     => [qw( clj )],+        cpp         => [qw( cpp cc cxx m hpp hh h hxx )],+        csharp      => [qw( cs )],+        css         => [qw( css )],+        delphi      => [qw( pas int dfm nfm dof dpk dproj groupproj bdsgroup bdsproj )],+        elisp       => [qw( el )],+        erlang      => [qw( erl hrl )],+        fortran     => [qw( f f77 f90 f95 f03 for ftn fpp )],+        go          => [qw( go )],+        groovy      => [qw( groovy gtmpl gpp grunit )],+        haskell     => [qw( hs lhs )],+        hh          => [qw( h )],+        html        => [qw( htm html shtml xhtml )],+        java        => [qw( java properties )],+        js          => [qw( js )],+        jsp         => [qw( jsp jspx jhtm jhtml )],+        lisp        => [qw( lisp lsp )],+        lua         => [qw( lua )],+        make        => q{Makefiles (including *.mk and *.mak)},+        mason       => [qw( mas mhtml mpl mtxt )],+        objc        => [qw( m h )],+        objcpp      => [qw( mm h )],+        ocaml       => [qw( ml mli )],+        parrot      => [qw( pir pasm pmc ops pod pg tg )],+        perl        => [qw( pl pm pm6 pod t psgi )],+        php         => [qw( php phpt php3 php4 php5 phtml)],+        plone       => [qw( pt cpt metadata cpy py )],+        python      => [qw( py )],+        rake        => q{Rakefiles},+        ruby        => [qw( rb rhtml rjs rxml erb rake spec )],+        scala       => [qw( scala )],+        scheme      => [qw( scm ss )],+        shell       => [qw( sh bash csh tcsh ksh zsh )],+        skipped     => q{Files, but not directories, normally skipped by ack (default: off)},+        smalltalk   => [qw( st )],+        sql         => [qw( sql ctl )],+        tcl         => [qw( tcl itcl itk )],+        tex         => [qw( tex cls sty )],+        text        => q{Text files, as defined by Perl's -T op (default: off)},+        tt          => [qw( tt tt2 ttml )],+        vb          => [qw( bas cls frm ctl vb resx )],+        verilog     => [qw( v vh sv )],+        vhdl        => [qw( vhd vhdl )],+        vim         => [qw( vim )],+        yaml        => [qw( yaml yml )],+        xml         => [qw( xml dtd xsl xslt ent )],+    );++    while ( my ($type,$exts) = each %mappings ) {+        if ( ref $exts ) {+            for my $ext ( @{$exts} ) {+                push( @{$types{$ext}}, $type );+            }+        }+    }+    # add manually Makefile extensions+    push @{$types{$_}}, 'make' for qw{ mk mak };++    # These have to be checked before any filehandle diddling.+    $output_to_pipe  = not -t *STDOUT;+    $input_from_pipe = -p STDIN;++    $is_cygwin       = ($^O eq 'cygwin');+    $is_windows      = ($^O =~ /MSWin32/);+    $dir_sep_chars   = $is_windows ? quotemeta( '\\/' ) : quotemeta( File::Spec->catfile( '', '' ) );+}+++sub read_ackrc {+    my @files = ( $ENV{ACKRC} );+    my @dirs =+        $is_windows+            ? ( $ENV{HOME}, $ENV{USERPROFILE} )+            : ( '~', $ENV{HOME} );+    for my $dir ( grep { defined } @dirs ) {+        for my $file ( '.ackrc', '_ackrc' ) {+            push( @files, bsd_glob( "$dir/$file", GLOB_TILDE ) );+        }+    }+    for my $filename ( @files ) {+        if ( defined $filename && -e $filename ) {+            open( my $fh, '<', $filename ) or App::Ack::die( "$filename: $!\n" );+            my @lines = grep { /./ && !/^\s*#/ } <$fh>;+            chomp @lines;+            close $fh or App::Ack::die( "$filename: $!\n" );++            # get rid of leading and trailing whitespaces+            for ( @lines ) {+               s/^\s+//;+               s/\s+$//;+            }++            return @lines;+        }+    }++    return;+}+++sub get_command_line_options {+    my %opt = (+        pager => $ENV{ACK_PAGER_COLOR} || $ENV{ACK_PAGER},+    );++    my $getopt_specs = {+        1                       => sub { $opt{1} = $opt{m} = 1 },+        'A|after-context=i'     => \$opt{after_context},+        'B|before-context=i'    => \$opt{before_context},+        'C|context:i'           => sub { shift; my $val = shift; $opt{before_context} = $opt{after_context} = ($val || 2) },+        'a|all-types'           => \$opt{all},+        'break!'                => \$opt{break},+        c                       => \$opt{count},+        'color|colour!'         => \$opt{color},+        'color-match=s'         => \$ENV{ACK_COLOR_MATCH},+        'color-filename=s'      => \$ENV{ACK_COLOR_FILENAME},+        'color-lineno=s'        => \$ENV{ACK_COLOR_LINENO},+        'column!'               => \$opt{column},+        count                   => \$opt{count},+        'env!'                  => sub { }, # ignore this option, it is handled beforehand+        f                       => \$opt{f},+        flush                   => \$opt{flush},+        'follow!'               => \$opt{follow},+        'g=s'                   => sub { shift; $opt{G} = shift; $opt{f} = 1 },+        'G=s'                   => \$opt{G},+        'group!'                => sub { shift; $opt{heading} = $opt{break} = shift },+        'heading!'              => \$opt{heading},+        'h|no-filename'         => \$opt{h},+        'H|with-filename'       => \$opt{H},+        'i|ignore-case'         => \$opt{i},+        'invert-file-match'     => \$opt{invert_file_match},+        'lines=s'               => sub { shift; my $val = shift; push @{$opt{lines}}, $val },+        'l|files-with-matches'  => \$opt{l},+        'L|files-without-matches' => sub { $opt{l} = $opt{v} = 1 },+        'm|max-count=i'         => \$opt{m},+        'match=s'               => \$opt{regex},+        'n|no-recurse'          => \$opt{n},+        o                       => sub { $opt{output} = '$&' },+        'output=s'              => \$opt{output},+        'pager=s'               => \$opt{pager},+        'nopager'               => sub { $opt{pager} = undef },+        'passthru'              => \$opt{passthru},+        'print0'                => \$opt{print0},+        'Q|literal'             => \$opt{Q},+        'r|R|recurse'           => sub { $opt{n} = 0 },+        'show-types'            => \$opt{show_types},+        'smart-case!'           => \$opt{smart_case},+        'sort-files'            => \$opt{sort_files},+        'u|unrestricted'        => \$opt{u},+        'v|invert-match'        => \$opt{v},+        'w|word-regexp'         => \$opt{w},++        'ignore-dirs=s'         => sub { shift; my $dir = remove_dir_sep( shift ); $ignore_dirs{$dir} = '--ignore-dirs' },+        'noignore-dirs=s'       => sub { shift; my $dir = remove_dir_sep( shift ); delete $ignore_dirs{$dir} },++        'version'   => sub { print_version_statement(); exit; },+        'help|?:s'  => sub { shift; show_help(@_); exit; },+        'help-types'=> sub { show_help_types(); exit; },+        'man'       => sub {+            require Pod::Usage;+            Pod::Usage::pod2usage({+                -verbose => 2,+                -exitval => 0,+            });+        },++        'type=s'    => sub {+            # Whatever --type=xxx they specify, set it manually in the hash+            my $dummy = shift;+            my $type = shift;+            my $wanted = ($type =~ s/^no//) ? 0 : 1; # must not be undef later++            if ( exists $type_wanted{ $type } ) {+                $type_wanted{ $type } = $wanted;+            }+            else {+                App::Ack::die( qq{Unknown --type "$type"} );+            }+        }, # type sub+    };++    # Stick any default switches at the beginning, so they can be overridden+    # by the command line switches.+    unshift @ARGV, split( ' ', $ENV{ACK_OPTIONS} ) if defined $ENV{ACK_OPTIONS};++    # first pass through options, looking for type definitions+    def_types_from_ARGV();++    for my $i ( filetypes_supported() ) {+        $getopt_specs->{ "$i!" } = \$type_wanted{ $i };+    }+++    my $parser = Getopt::Long::Parser->new();+    $parser->configure( 'bundling', 'no_ignore_case', );+    $parser->getoptions( %{$getopt_specs} ) or+        App::Ack::die( 'See ack --help, ack --help-types or ack --man for options.' );++    my $to_screen = not output_to_pipe();+    my %defaults = (+        all            => 0,+        color          => $to_screen,+        follow         => 0,+        break          => $to_screen,+        heading        => $to_screen,+        before_context => 0,+        after_context  => 0,+    );+    if ( $is_windows && $defaults{color} && not $ENV{ACK_PAGER_COLOR} ) {+        if ( $ENV{ACK_PAGER} || not eval { require Win32::Console::ANSI } ) {+            $defaults{color} = 0;+        }+    }+    if ( $to_screen && $ENV{ACK_PAGER_COLOR} ) {+        $defaults{color} = 1;+    }++    while ( my ($key,$value) = each %defaults ) {+        if ( not defined $opt{$key} ) {+            $opt{$key} = $value;+        }+    }++    if ( defined $opt{m} && $opt{m} <= 0 ) {+        App::Ack::die( '-m must be greater than zero' );+    }++    for ( qw( before_context after_context ) ) {+        if ( defined $opt{$_} && $opt{$_} < 0 ) {+            App::Ack::die( "--$_ may not be negative" );+        }+    }++    if ( defined( my $val = $opt{output} ) ) {+        $opt{output} = eval qq[ sub { "$val" } ];+    }+    if ( defined( my $l = $opt{lines} ) ) {+        # --line=1 --line=5 is equivalent to --line=1,5+        my @lines = split( /,/, join( ',', @{$l} ) );++        # --line=1-3 is equivalent to --line=1,2,3+        @lines = map {+            my @ret;+            if ( /-/ ) {+                my ($from, $to) = split /-/, $_;+                if ( $from > $to ) {+                    App::Ack::warn( "ignoring --line=$from-$to" );+                    @ret = ();+                }+                else {+                    @ret = ( $from .. $to );+                }+            }+            else {+                @ret = ( $_ );+            };+            @ret+        } @lines;++        if ( @lines ) {+            my %uniq;+            @uniq{ @lines } = ();+            $opt{lines} = [ sort { $a <=> $b } keys %uniq ];   # numerical sort and each line occurs only once!+        }+        else {+            # happens if there are only ignored --line directives+            App::Ack::die( 'All --line options are invalid.' );+        }+    }++    return \%opt;+}+++sub def_types_from_ARGV {+    my @typedef;++    my $parser = Getopt::Long::Parser->new();+        # pass_through   => leave unrecognized command line arguments alone+        # no_auto_abbrev => otherwise -c is expanded and not left alone+    $parser->configure( 'no_ignore_case', 'pass_through', 'no_auto_abbrev' );+    $parser->getoptions(+        'type-set=s' => sub { shift; push @typedef, ['c', shift] },+        'type-add=s' => sub { shift; push @typedef, ['a', shift] },+    ) or App::Ack::die( 'See ack --help or ack --man for options.' );++    for my $td (@typedef) {+        my ($type, $ext) = split /=/, $td->[1];++        if ( $td->[0] eq 'c' ) {+            # type-set+            if ( exists $mappings{$type} ) {+                # can't redefine types 'make', 'skipped', 'text' and 'binary'+                App::Ack::die( qq{--type-set: Builtin type "$type" cannot be changed.} )+                    if ref $mappings{$type} ne 'ARRAY';++                delete_type($type);+            }+        }+        else {+            # type-add++            # can't append to types 'make', 'skipped', 'text' and 'binary'+            App::Ack::die( qq{--type-add: Builtin type "$type" cannot be changed.} )+                if exists $mappings{$type} && ref $mappings{$type} ne 'ARRAY';++            App::Ack::warn( qq{--type-add: Type "$type" does not exist, creating with "$ext" ...} )+                unless exists $mappings{$type};+        }++        my @exts = split /,/, $ext;+        s/^\.// for @exts;++        if ( !exists $mappings{$type} || ref($mappings{$type}) eq 'ARRAY' ) {+            push @{$mappings{$type}}, @exts;+            for my $e ( @exts ) {+                push @{$types{$e}}, $type;+            }+        }+        else {+            App::Ack::die( qq{Cannot append to type "$type".} );+        }+    }++    return;+}+++sub delete_type {+    my $type = shift;++    App::Ack::die( qq{Internal error: Cannot delete builtin type "$type".} )+        unless ref $mappings{$type} eq 'ARRAY';++    delete $mappings{$type};+    delete $type_wanted{$type};+    for my $ext ( keys %types ) {+        $types{$ext} = [ grep { $_ ne $type } @{$types{$ext}} ];+    }+}+++sub ignoredir_filter {+    return !exists $ignore_dirs{$_} && !exists $ignore_dirs{$File::Next::dir};+}+++sub remove_dir_sep {+    my $path = shift;+    $path =~ s/[$dir_sep_chars]$//;++    return $path;+}+++use constant TEXT => 'text';++sub filetypes {+    my $filename = shift;++    my $basename = $filename;+    $basename =~ s{.*[$dir_sep_chars]}{};++    return 'skipped' unless is_searchable( $basename );++    my $lc_basename = lc $basename;+    return ('make',TEXT)        if $lc_basename eq 'makefile' || $lc_basename eq 'gnumakefile';+    return ('rake','ruby',TEXT) if $lc_basename eq 'rakefile';++    # If there's an extension, look it up+    if ( $filename =~ m{\.([^\.$dir_sep_chars]+)$}o ) {+        my $ref = $types{lc $1};+        return (@{$ref},TEXT) if $ref;+    }++    # At this point, we can't tell from just the name.  Now we have to+    # open it and look inside.++    return unless -e $filename;+    # From Elliot Shank:+    #     I can't see any reason that -r would fail on these-- the ACLs look+    #     fine, and no program has any of them open, so the busted Windows+    #     file locking model isn't getting in there.  If I comment the if+    #     statement out, everything works fine+    # So, for cygwin, don't bother trying to check for readability.+    if ( !$is_cygwin ) {+        if ( !-r $filename ) {+            App::Ack::warn( "$filename: Permission denied" );+            return;+        }+    }++    return 'binary' if -B $filename;++    # If there's no extension, or we don't recognize it, check the shebang line+    my $fh;+    if ( !open( $fh, '<', $filename ) ) {+        App::Ack::warn( "$filename: $!" );+        return;+    }+    my $header = <$fh>;+    close $fh;++    if ( $header =~ /^#!/ ) {+        return ($1,TEXT)       if $header =~ /\b(ruby|lua|p(?:erl|hp|ython))-?(\d[\d.]*)?\b/;+        return ('shell',TEXT)  if $header =~ /\b(?:ba|t?c|k|z)?sh\b/;+    }+    else {+        return ('xml',TEXT)    if $header =~ /\Q<?xml /i;+    }++    return (TEXT);+}+++sub is_searchable {+    my $filename = shift;++    # If these are updated, update the --help message+    return if $filename =~ /[.]bak$/;+    return if $filename =~ /~$/;+    return if $filename =~ m{^#.*#$}o;+    return if $filename =~ m{^core\.\d+$}o;+    return if $filename =~ m{[._].*\.swp$}o;+    return if $filename =~ /[.-]min\.js$/;++    return 1;+}+++sub build_regex {+    my $str = shift;+    my $opt = shift;++    defined $str or App::Ack::die( 'No regular expression found.' );++    $str = quotemeta( $str ) if $opt->{Q};+    if ( $opt->{w} ) {+        $str = "\\b$str" if $str =~ /^\w/;+        $str = "$str\\b" if $str =~ /\w$/;+    }++    my $regex_is_lc = $str eq lc $str;+    if ( $opt->{i} || ($opt->{smart_case} && $regex_is_lc) ) {+        $str = "(?i)$str";+    }++    return $str;+}+++sub check_regex {+    my $regex = shift;++    return unless defined $regex;++    eval { qr/$regex/ };+    if ($@) {+        (my $error = $@) =~ s/ at \S+ line \d+.*//;+        chomp($error);+        App::Ack::die( "Invalid regex '$regex':\n  $error" );+    }++    return;+}+++++sub warn {+    return CORE::warn( _my_program(), ': ', @_, "\n" );+}+++sub die {+    return CORE::die( _my_program(), ': ', @_, "\n" );+}++sub _my_program {+    require File::Basename;+    return File::Basename::basename( $0 );+}++++sub filetypes_supported {+    return keys %mappings;+}++sub _get_thpppt {+    my $y = q{_   /|,\\'!.x',=(www)=,   U   };+    $y =~ tr/,x!w/\nOo_/;+    return $y;+}++sub _thpppt {+    my $y = _get_thpppt();+    App::Ack::print( "$y ack $_[0]!\n" );+    exit 0;+}++sub _bar {+    my $x;+    $x = <<'_BAR';+ 6?!I'7!I"?%+!+ 3~!I#7#I"7#I!?!+!="+"="+!:!+ 2?#I!7!I!?#I!7!I"+"=%+"=#+ 1?"+!?*+!=#~"=!+#?"="+!+ 0?"+!?"I"?&+!="~!=!~"=!+%="+"+ /I!+!?)+!?!+!=$~!=!~!="+!="+"?!="?!+ .?%I"?%+%='?!=#~$="+ ,,!?%I"?(+$=$~!=#:"~$:!~!+ ,I!?!I!?"I"?!+#?"+!?!+#="~$:!~!:!~!:!,!:!,":#~!+ +I!?&+!="+!?#+$=!~":!~!:!~!:!,!:#,!:!,%:"+ *+!I!?!+$=!+!=!+!?$+#=!~":!~":#,$:",#:!,!:!+ *I!?"+!?!+!=$+!?#+#=#~":$,!:",!:!,&:"+ )I!?$=!~!=#+"?!+!=!+!=!~!="~!:!~":!,'.!,%:!~!+ (=!?"+!?!=!~$?"+!?!+!=#~"=",!="~$,$.",#.!:!=!+ (I"+"="~"=!+&=!~"=!~!,!~!+!=!?!+!?!=!I!?!+"=!.",!.!,":!+ %I$?!+!?!=%+!~!+#~!=!~#:#=!~!+!~!=#:!,%.!,!.!:"+ $I!?!=!?!I!+!?"+!=!~!=!~!?!I!?!=!+!=!~#:",!~"=!~!:"~!=!:",&:" '-/+ $?!+!I!?"+"=!+"~!,!:"+#~#:#,"=!~"=!,!~!,!.",!:".!:! */! !I!t!'!s! !a! !g!r!e!p!!! !/!+ $+"=!+!?!+"~!=!:!~!:"I!+!,!~!=!:!~!,!:!,$:!~".&:"~!,# (-/+ %~!=!~!=!:!.!+"~!:!,!.!,!~!=!:$.!,":!,!.!:!~!,!:!=!.#="~!,!:" ./!+ %=!~!?!+"?"+!=!~",!.!:!?!~!.!:!,!:!,#.!,!:","~!:!=!~!=!:",!~! ./!+ %+"~":!~!=#~!:!~!,!.!~!:",!~!=!~!.!:!,!.",!:!,":!=":!.!,!:!7! -/!+ %~",!:".#:!=!:!,!:"+!:!~!:!.!,!~!,!.#,!.!,$:"~!,":"~!=! */!+ &=!~!=#+!=!~",!.!:",#:#,!.",+:!,!.",!=!+!?!+ &~!=!~!=!~!:"~#:",!.!,#~!:!.!+!,!.",$.",$.#,!+!I!?!+ &~!="~!:!~":!~",!~!=!~":!,!:!~!,!:!,&.$,#."+!?!I!?!I!+ &~!=!~!=!+!,!:!~!:!=!,!:!~&:$,!.!,".!,".!,#."~!+!?$I!+ &~!=!~!="~!=!:!~":!,!~%:#,!:",!.!,#.",#I!7"I!?!+!?"I"+ &+!I!7!:#~"=!~!:!,!:"~$.!=!.!,!~!,$.#,!~!7!I#?!+!?"I"7!+ %7#?!+!~!:!=!~!=!~":!,!:"~":#.!,)7#I"?"I!7&+ %7#I!=":!=!~!:"~$:"~!:#,!:!,!:!~!:#,!7#I!?#7)+ $7$+!,!~!=#~!:!~!:!~$:#,!.!~!:!=!,":!7#I"?#7+=!?!+ $7#I!~!,!~#=!~!:"~!:!,!:!,#:!=!~",":!7$I!?#I!7*+!=!+"+ "I!7$I!,":!,!.!=":$,!:!,$:$7$I!+!?"I!7+?"I!7!I!7!,!+ !,!7%I!:",!."~":!,&.!,!:!~!I!7$I!+!?"I!7,?!I!7',!+ !7(,!.#~":!,%.!,!7%I!7!?#I"7,+!?!7*+7+:!,!~#,"=!7'I!?#I"7/+!7++77I!+!7!?!7!I"71+!7,+_BAR++    $x =~ s/(.)(.)/$1x(ord($2)-32)/eg;+    App::Ack::print( $x );+    exit 0;+}++sub _key {+    my $str = lc shift;+    $str =~ s/[^a-z]//g;++    return $str;+}+++sub show_help {+    my $help_arg = shift || 0;++    return show_help_types() if $help_arg =~ /^types?/;++    my $ignore_dirs = _listify( sort { _key($a) cmp _key($b) } keys %ignore_dirs );++    App::Ack::print( <<"END_OF_HELP" );+Usage: ack [OPTION]... PATTERN [FILE]++Search for PATTERN in each source file in the tree from cwd on down.+If [FILES] is specified, then only those files/directories are checked.+ack may also search STDIN, but only if no FILE are specified, or if+one of FILES is "-".++Default switches may be specified in ACK_OPTIONS environment variable or+an .ackrc file. If you want no dependency on the environment, turn it+off with --noenv.++Example: ack -i select++Searching:+  -i, --ignore-case     Ignore case distinctions in PATTERN+  --[no]smart-case      Ignore case distinctions in PATTERN,+                        only if PATTERN contains no upper case+                        Ignored if -i is specified+  -v, --invert-match    Invert match: select non-matching lines+  -w, --word-regexp     Force PATTERN to match only whole words+  -Q, --literal         Quote all metacharacters; PATTERN is literal++Search output:+  --line=NUM            Only print line(s) NUM of each file+  -l, --files-with-matches+                        Only print filenames containing matches+  -L, --files-without-matches+                        Only print filenames with no matches+  -o                    Show only the part of a line matching PATTERN+                        (turns off text highlighting)+  --passthru            Print all lines, whether matching or not+  --output=expr         Output the evaluation of expr for each line+                        (turns off text highlighting)+  --match PATTERN       Specify PATTERN explicitly.+  -m, --max-count=NUM   Stop searching in each file after NUM matches+  -1                    Stop searching after one match of any kind+  -H, --with-filename   Print the filename for each match+  -h, --no-filename     Suppress the prefixing filename on output+  -c, --count           Show number of lines matching per file+  --column              Show the column number of the first match++  -A NUM, --after-context=NUM+                        Print NUM lines of trailing context after matching+                        lines.+  -B NUM, --before-context=NUM+                        Print NUM lines of leading context before matching+                        lines.+  -C [NUM], --context[=NUM]+                        Print NUM lines (default 2) of output context.++  --print0              Print null byte as separator between filenames,+                        only works with -f, -g, -l, -L or -c.++File presentation:+  --pager=COMMAND       Pipes all ack output through COMMAND.  For example,+                        --pager="less -R".  Ignored if output is redirected.+  --nopager             Do not send output through a pager.  Cancels any+                        setting in ~/.ackrc, ACK_PAGER or ACK_PAGER_COLOR.+  --[no]heading         Print a filename heading above each file's results.+                        (default: on when used interactively)+  --[no]break           Print a break between results from different files.+                        (default: on when used interactively)+  --group               Same as --heading --break+  --nogroup             Same as --noheading --nobreak+  --[no]color           Highlight the matching text (default: on unless+                        output is redirected, or on Windows)+  --[no]colour          Same as --[no]color+  --color-filename=COLOR+  --color-match=COLOR+  --color-lineno=COLOR  Set the color for filenames, matches, and line numbers.+  --flush               Flush output immediately, even when ack is used+                        non-interactively (when output goes to a pipe or+                        file).++File finding:+  -f                    Only print the files found, without searching.+                        The PATTERN must not be specified.+  -g REGEX              Same as -f, but only print files matching REGEX.+  --sort-files          Sort the found files lexically.+  --invert-file-match   Print/search handle files that do not match -g/-G.+  --show-types          Show which types each file has.++File inclusion/exclusion:+  -a, --all-types       All file types searched;+                        Ignores CVS, .svn and other ignored directories+  -u, --unrestricted    All files and directories searched+  --[no]ignore-dir=name Add/Remove directory from the list of ignored dirs+  -r, -R, --recurse     Recurse into subdirectories (ack's default behavior)+  -n, --no-recurse      No descending into subdirectories+  -G REGEX              Only search files that match REGEX++  --perl                Include only Perl files.+  --type=perl           Include only Perl files.+  --noperl              Exclude Perl files.+  --type=noperl         Exclude Perl files.+                        See "ack --help type" for supported filetypes.++  --type-set TYPE=.EXTENSION[,.EXT2[,...]]+                        Files with the given EXTENSION(s) are recognized as+                        being of type TYPE. This replaces an existing+                        definition for type TYPE.+  --type-add TYPE=.EXTENSION[,.EXT2[,...]]+                        Files with the given EXTENSION(s) are recognized as+                        being of (the existing) type TYPE++  --[no]follow          Follow symlinks.  Default is off.++  Directories ignored by default:+    $ignore_dirs++  Files not checked for type:+    /~\$/            - Unix backup files+    /#.+#\$/         - Emacs swap files+    /[._].*\\.swp\$/ - Vi(m) swap files+    /core\\.\\d+\$/  - core dumps+    /[.-]min\\.js\$/  - Minified javascript files++Miscellaneous:+  --noenv               Ignore environment variables and ~/.ackrc+  --help                This help+  --man                 Man page+  --version             Display version & copyright+  --thpppt              Bill the Cat+  --bar                 The warning admiral++Exit status is 0 if match, 1 if no match.++This is version $VERSION of ack.+END_OF_HELP++    return;+ }++++sub show_help_types {+    App::Ack::print( <<'END_OF_HELP' );+Usage: ack [OPTION]... PATTERN [FILES]++The following is the list of filetypes supported by ack.  You can+specify a file type with the --type=TYPE format, or the --TYPE+format.  For example, both --type=perl and --perl work.++Note that some extensions may appear in multiple types.  For example,+.pod files are both Perl and Parrot.++END_OF_HELP++    my @types = filetypes_supported();+    my $maxlen = 0;+    for ( @types ) {+        $maxlen = length if $maxlen < length;+    }+    for my $type ( sort @types ) {+        next if $type =~ /^-/; # Stuff to not show+        my $ext_list = $mappings{$type};++        if ( ref $ext_list ) {+            $ext_list = join( ' ', map { ".$_" } @{$ext_list} );+        }+        App::Ack::print( sprintf( "    --[no]%-*.*s %s\n", $maxlen, $maxlen, $type, $ext_list ) );+    }++    return;+}++sub _listify {+    my @whats = @_;++    return '' if !@whats;++    my $end = pop @whats;+    my $str = @whats ? join( ', ', @whats ) . " and $end" : $end;++    no warnings 'once';+    require Text::Wrap;+    $Text::Wrap::columns = 75;+    return Text::Wrap::wrap( '', '    ', $str );+}+++sub get_version_statement {+    require Config;++    my $copyright = get_copyright();+    my $this_perl = $Config::Config{perlpath};+    if ($^O ne 'VMS') {+        my $ext = $Config::Config{_exe};+        $this_perl .= $ext unless $this_perl =~ m/$ext$/i;+    }+    my $ver = sprintf( '%vd', $^V );++    return <<"END_OF_VERSION";+ack $VERSION+Running under Perl $ver at $this_perl++$copyright++This program is free software.  You may modify or distribute it+under the terms of the Artistic License v2.0.+END_OF_VERSION+}+++sub print_version_statement {+    App::Ack::print( get_version_statement() );++    return;+}+++sub get_copyright {+    return $COPYRIGHT;+}+++sub load_colors {+    eval 'use Term::ANSIColor ()';++    $ENV{ACK_COLOR_MATCH}    ||= 'black on_yellow';+    $ENV{ACK_COLOR_FILENAME} ||= 'bold green';+    $ENV{ACK_COLOR_LINENO}   ||= 'bold yellow';++    return;+}+++sub is_interesting {+    return if /^\./;++    my $include;++    for my $type ( filetypes( $File::Next::name ) ) {+        if ( defined $type_wanted{$type} ) {+            if ( $type_wanted{$type} ) {+                $include = 1;+            }+            else {+                return;+            }+        }+    }++    return $include;+}++++# print subs added in order to make it easy for a third party+# module (such as App::Wack) to redefine the display methods+# and show the results in a different way.+sub print                   { print {$fh} @_ }+sub print_first_filename    { App::Ack::print( $_[0], "\n" ) }+sub print_blank_line        { App::Ack::print( "\n" ) }+sub print_separator         { App::Ack::print( "--\n" ) }+sub print_filename          { App::Ack::print( $_[0], $_[1] ) }+sub print_line_no           { App::Ack::print( $_[0], $_[1] ) }+sub print_column_no         { App::Ack::print( $_[0], $_[1] ) }+sub print_count {+    my $filename = shift;+    my $nmatches = shift;+    my $ors = shift;+    my $count = shift;+    my $show_filename = shift;++    if ($show_filename) {+        App::Ack::print( $filename );+        App::Ack::print( ':', $nmatches ) if $count;+    }+    else {+        App::Ack::print( $nmatches ) if $count;+    }+    App::Ack::print( $ors );+}++sub print_count0 {+    my $filename = shift;+    my $ors = shift;+    my $show_filename = shift;++    if ($show_filename) {+        App::Ack::print( $filename, ':0', $ors );+    }+    else {+        App::Ack::print( '0', $ors );+    }+}++++{+    my $filename;+    my $regex;+    my $display_filename;++    my $keep_context;++    my $last_output_line;             # number of the last line that has been output+    my $any_output;                   # has there been any output for the current file yet+    my $context_overall_output_count; # has there been any output at all++sub search_resource {+    my $res = shift;+    my $opt = shift;++    $filename = $res->name();++    my $v = $opt->{v};+    my $passthru = $opt->{passthru};+    my $max = $opt->{m};+    my $nmatches = 0;++    $display_filename = undef;++    # for --line processing+    my $has_lines = 0;+    my @lines;+    if ( defined $opt->{lines} ) {+        $has_lines = 1;+        @lines = ( @{$opt->{lines}}, -1 );+        undef $regex; # Don't match when printing matching line+    }+    else {+        $regex = qr/$opt->{regex}/;+    }++    # for context processing+    $last_output_line = -1;+    $any_output = 0;+    my $before_context = $opt->{before_context};+    my $after_context  = $opt->{after_context};++    $keep_context = ($before_context || $after_context) && !$passthru;++    my @before;+    my $before_starts_at_line;+    my $after = 0; # number of lines still to print after a match++    while ( $res->next_text ) {+        # XXX Optimize away the case when there are no more @lines to find.+        # XXX $has_lines, $passthru and $v never change.  Optimize.+        if ( $has_lines+               ? $. != $lines[0]  # $lines[0] should be a scalar+               : $v ? m/$regex/ : !m/$regex/ ) {+            if ( $passthru ) {+                App::Ack::print( $_ );+                next;+            }++            if ( $keep_context ) {+                if ( $after ) {+                    print_match_or_context( $opt, 0, $., $-[0], $+[0], $_ );+                    $after--;+                }+                elsif ( $before_context ) {+                    if ( @before ) {+                        if ( @before >= $before_context ) {+                            shift @before;+                            ++$before_starts_at_line;+                        }+                    }+                    else {+                        $before_starts_at_line = $.;+                    }+                    push @before, $_;+                }+                last if $max && ( $nmatches >= $max ) && !$after;+            }+            next;+        } # not a match++        ++$nmatches;++        # print an empty line as a divider before first line in each file (not before the first file)+        if ( !$any_output && $opt->{show_filename} && $opt->{break} && defined( $context_overall_output_count ) ) {+            App::Ack::print_blank_line();+        }++        shift @lines if $has_lines;++        if ( $res->is_binary ) {+            App::Ack::print( "Binary file $filename matches\n" );+            last;+        }+        if ( $keep_context ) {+            if ( @before ) {+                print_match_or_context( $opt, 0, $before_starts_at_line, $-[0], $+[0], @before );+                @before = ();+                $before_starts_at_line = 0;+            }+            if ( $max && $nmatches > $max ) {+                --$after;+            }+            else {+                $after = $after_context;+            }+        }+        print_match_or_context( $opt, 1, $., $-[0], $+[0], $_ );++        last if $max && ( $nmatches >= $max ) && !$after;+    } # while++    return $nmatches;+}   # search_resource()++++sub print_match_or_context {+    my $opt         = shift; # opts array+    my $is_match    = shift; # is there a match on the line?+    my $line_no     = shift;+    my $match_start = shift;+    my $match_end   = shift;++    my $color         = $opt->{color};+    my $heading       = $opt->{heading};+    my $show_filename = $opt->{show_filename};+    my $show_column   = $opt->{column};++    if ( $show_filename ) {+        if ( not defined $display_filename ) {+            $display_filename =+                $color+                    ? Term::ANSIColor::colored( $filename, $ENV{ACK_COLOR_FILENAME} )+                    : $filename;+            if ( $heading && !$any_output ) {+                App::Ack::print_first_filename($display_filename);+            }+        }+    }++    my $sep = $is_match ? ':' : '-';+    my $output_func = $opt->{output};+    for ( @_ ) {+        if ( $keep_context && !$output_func ) {+            if ( ( $last_output_line != $line_no - 1 ) &&+                ( $any_output || ( !$heading && defined( $context_overall_output_count ) ) ) ) {+                App::Ack::print_separator();+            }+            # to ensure separators between different files when --noheading++            $last_output_line = $line_no;+        }++        if ( $show_filename ) {+            App::Ack::print_filename($display_filename, $sep) if not $heading;+            my $display_line_no =+                $color+                    ? Term::ANSIColor::colored( $line_no, $ENV{ACK_COLOR_LINENO} )+                    : $line_no;+            App::Ack::print_line_no($display_line_no, $sep);+        }++        if ( $output_func ) {+            while ( /$regex/go ) {+                App::Ack::print( $output_func->() . "\n" );+            }+        }+        else {+            if ( $color && $is_match && $regex &&+                 s/$regex/Term::ANSIColor::colored( substr($_, $-[0], $+[0] - $-[0]), $ENV{ACK_COLOR_MATCH} )/eg ) {+                # At the end of the line reset the color and remove newline+                s/[\r\n]*\z/\e[0m\e[K/;+            }+            else {+                # remove any kind of newline at the end of the line+                s/[\r\n]*\z//;+            }+            if ( $show_column ) {+                App::Ack::print_column_no( $match_start+1, $sep );+            }+            App::Ack::print($_ . "\n");+        }+        $any_output = 1;+        ++$context_overall_output_count;+        ++$line_no;+    }++    return;+} # print_match_or_context()++} # scope around search_resource() and print_match_or_context()+++TOTAL_COUNT_SCOPE: {+my $total_count;++sub get_total_count {+    return $total_count;+}++sub reset_total_count {+    $total_count = 0;+}+++sub search_and_list {+    my $res = shift;+    my $opt = shift;++    my $nmatches = 0;+    my $count = $opt->{count};+    my $ors = $opt->{print0} ? "\0" : "\n"; # output record separator+    my $show_filename = $opt->{show_filename};++    my $regex = qr/$opt->{regex}/;++    if ( $opt->{v} ) {+        while ( $res->next_text ) {+            if ( /$regex/ ) {+                return 0 unless $count;+            }+            else {+                ++$nmatches;+            }+        }+    }+    else {+        while ( $res->next_text ) {+            if ( /$regex/ ) {+                ++$nmatches;+                last unless $count;+            }+        }+    }++    if ( $opt->{show_total} ) {+        $total_count += $nmatches;+    }+    else {+        if ( $nmatches ) {+            App::Ack::print_count( $res->name, $nmatches, $ors, $count, $show_filename );+        }+        elsif ( $count && !$opt->{l} ) {+            App::Ack::print_count0( $res->name, $ors, $show_filename );+        }+    }++    return $nmatches ? 1 : 0;+}   # search_and_list()++} # scope around $total_count++++sub filetypes_supported_set {+    return grep { defined $type_wanted{$_} && ($type_wanted{$_} == 1) } filetypes_supported();+}++++sub print_files {+    my $iter = shift;+    my $opt = shift;++    my $ors = $opt->{print0} ? "\0" : "\n";++    my $nmatches = 0;+    while ( defined ( my $file = $iter->() ) ) {+        App::Ack::print $file, $opt->{show_types} ? " => " . join( ',', filetypes( $file ) ) : (),  $ors;+        $nmatches++;+        last if $opt->{1};+    }++    return $nmatches;+}+++sub print_files_with_matches {+    my $iter = shift;+    my $opt = shift;++    # if we have -l and only 1 file given on command line (this means+    # show_filename is set to 0), we want to see the filename nevertheless+    $opt->{show_filename} = 1 if $opt->{l};++    $opt->{show_filename} = 0 if $opt->{h};+    $opt->{show_filename} = 1 if $opt->{H};++    # abuse options to hand in the show_total parameter to search_and_list+    $opt->{show_total} = $opt->{count} && !$opt->{show_filename};+    reset_total_count();++    my $nmatches = 0;+    while ( defined ( my $filename = $iter->() ) ) {+        my $repo = App::Ack::Repository::Basic->new( $filename );+        my $res;+        while ( $res = $repo->next_resource() ) {+            $nmatches += search_and_list( $res, $opt );+            $res->close();+            last if $nmatches && $opt->{1};+        }+        $repo->close();+    }++    if ( $nmatches && $opt->{show_total} ) {+        App::Ack::print_count('', get_total_count(), "\n", 1, 0  )+    }++    return $nmatches;+}+++sub print_matches {+    my $iter = shift;+    my $opt = shift;++    $opt->{show_filename} = 0 if $opt->{h};+    $opt->{show_filename} = 1 if $opt->{H};++    my $nmatches = 0;+    while ( defined ( my $filename = $iter->() ) ) {+        my $repo;+        my $tarballs_work = 0;+        if ( $tarballs_work && $filename =~ /\.tar\.gz$/ ) {+            App::Ack::die( 'Not working here yet' );+            require App::Ack::Repository::Tar; # XXX Error checking+            $repo = App::Ack::Repository::Tar->new( $filename );+        }+        else {+            $repo = App::Ack::Repository::Basic->new( $filename );+        }+        $repo or next;++        while ( my $res = $repo->next_resource() ) {+            my $needs_line_scan;+            if ( $opt->{regex} && !$opt->{passthru} ) {+                $needs_line_scan = $res->needs_line_scan( $opt );+                if ( $needs_line_scan ) {+                    $res->reset();+                }+            }+            else {+                $needs_line_scan = 1;+            }+            if ( $needs_line_scan ) {+                $nmatches += search_resource( $res, $opt );+            }+            $res->close();+        }+        last if $nmatches && $opt->{1};+        $repo->close();+    }+    return  $nmatches;+}+++sub filetype_setup {+    my $filetypes_supported_set = filetypes_supported_set();+    # If anyone says --no-whatever, we assume all other types must be on.+    if ( !$filetypes_supported_set ) {+        for my $i ( keys %type_wanted ) {+            $type_wanted{$i} = 1 unless ( defined( $type_wanted{$i} ) || $i eq 'binary' || $i eq 'text' || $i eq 'skipped' );+        }+    }+    return;+}+++EXPAND_FILENAMES_SCOPE: {+    my $filter;++    sub expand_filenames {+        my $argv = shift;++        my $attr;+        my @files;++        foreach my $pattern ( @{$argv} ) {+            my @results = bsd_glob( $pattern );++            if (@results == 0) {+                @results = $pattern; # Glob didn't match, pass it thru unchanged+            }+            elsif ( (@results > 1) or ($results[0] ne $pattern) ) {+                if (not defined $filter) {+                    eval 'require Win32::File;';+                    if ($@) {+                        $filter = 0;+                    }+                    else {+                        $filter = Win32::File::HIDDEN()|Win32::File::SYSTEM();+                    }+                } # end unless we've tried to load Win32::File+                if ( $filter ) {+                    # Filter out hidden and system files:+                    @results = grep { not(Win32::File::GetAttributes($_, $attr) and $attr & $filter) } @results;+                    App::Ack::warn( "$pattern: Matched only hidden files" ) unless @results;+                } # end if we can filter by file attributes+            } # end elsif this pattern got expanded++            push @files, @results;+        } # end foreach pattern++        return \@files;+    } # end expand_filenames+} # EXPAND_FILENAMES_SCOPE++++sub get_starting_points {+    my $argv = shift;+    my $opt = shift;++    my @what;++    if ( @{$argv} ) {+        @what = @{ $is_windows ? expand_filenames($argv) : $argv };+        $_ = File::Next::reslash( $_ ) for @what;++        # Show filenames unless we've specified one single file+        $opt->{show_filename} = (@what > 1) || (!-f $what[0]);+    }+    else {+        @what = '.'; # Assume current directory+        $opt->{show_filename} = 1;+    }++    for my $start_point (@what) {+        App::Ack::warn( "$start_point: No such file or directory" ) unless -e $start_point;+    }+    return \@what;+}++sub _match {+    my ( $target, $expression, $invert_flag ) = @_;++    if ( $invert_flag ) {+        return $target !~ $expression;+    }+    else {+        return $target =~ $expression;+    }+}+++sub get_iterator {+    my $what = shift;+    my $opt  = shift;++    # Starting points are always searched, no matter what+    my %starting_point = map { ($_ => 1) } @{$what};++    my $g_regex = defined $opt->{G} ? qr/$opt->{G}/ : undef;+    my $file_filter;++    if ( $g_regex ) {+        $file_filter+            = $opt->{u}   ? sub { _match( $File::Next::name, qr/$g_regex/, $opt->{invert_file_match} ) }    # XXX Maybe this should be a 1, no?+            : $opt->{all} ? sub { $starting_point{ $File::Next::name } || ( _match( $File::Next::name, qr/$g_regex/, $opt->{invert_file_match} ) && is_searchable( $_ ) ) }+            :               sub { $starting_point{ $File::Next::name } || ( _match( $File::Next::name, qr/$g_regex/, $opt->{invert_file_match} ) && is_interesting( @ _) ) }+            ;+    }+    else {+        $file_filter+            = $opt->{u}   ? sub {1}+            : $opt->{all} ? sub { $starting_point{ $File::Next::name } || is_searchable( $_ ) }+            :               sub { $starting_point{ $File::Next::name } || is_interesting( @_ ) }+            ;+    }++    my $descend_filter+        = $opt->{n} ? sub {0}+        : $opt->{u} ? sub {1}+        : \&ignoredir_filter;++    my $iter =+        File::Next::files( {+            file_filter     => $file_filter,+            descend_filter  => $descend_filter,+            error_handler   => sub { my $msg = shift; App::Ack::warn( $msg ) },+            sort_files      => $opt->{sort_files},+            follow_symlinks => $opt->{follow},+        }, @{$what} );+    return $iter;+}+++sub set_up_pager {+    my $command = shift;++    return if App::Ack::output_to_pipe();++    my $pager;+    if ( not open( $pager, '|-', $command ) ) {+        App::Ack::die( qq{Unable to pipe to pager "$command": $!} );+    }+    $fh = $pager;++    return;+}+++sub input_from_pipe {+    return $input_from_pipe;+}++++sub output_to_pipe {+    return $output_to_pipe;+}+++sub exit_from_ack {+    my $nmatches = shift;++    my $rc = $nmatches ? 0 : 1;+    exit $rc;+}++++1; # End of App::Ack+package App::Ack::Repository;+++use warnings;+use strict;++sub FAIL {+    require Carp;+    Carp::confess( 'Must be overloaded' );+}+++sub new {+    FAIL();+}+++sub next_resource {+    FAIL();+}+++sub close {+    FAIL();+}++1;+package App::Ack::Resource;+++use warnings;+use strict;++sub FAIL {+    require Carp;+    Carp::confess( 'Must be overloaded' );+}+++sub new {+    FAIL();+}+++sub name {+    FAIL();+}+++sub is_binary {+    FAIL();+}++++sub needs_line_scan {+    FAIL();+}+++sub reset {+    FAIL();+}+++sub next_text {+    FAIL();+}+++sub close {+    FAIL();+}++1;+package App::Ack::Plugin::Basic;++++package App::Ack::Resource::Basic;+++use warnings;+use strict;+++our @ISA = qw( App::Ack::Resource );+++sub new {+    my $class    = shift;+    my $filename = shift;++    my $self = bless {+        filename        => $filename,+        fh              => undef,+        could_be_binary => undef,+        opened          => undef,+        id              => undef,+    }, $class;++    if ( $self->{filename} eq '-' ) {+        $self->{fh} = *STDIN;+        $self->{could_be_binary} = 0;+    }+    else {+        if ( !open( $self->{fh}, '<', $self->{filename} ) ) {+            App::Ack::warn( "$self->{filename}: $!" );+            return;+        }+        $self->{could_be_binary} = 1;+    }++    return $self;+}+++sub name {+    my $self = shift;++    return $self->{filename};+}+++sub is_binary {+    my $self = shift;++    if ( $self->{could_be_binary} ) {+        return -B $self->{filename};+    }++    return 0;+}++++sub needs_line_scan {+    my $self  = shift;+    my $opt   = shift;++    return 1 if $opt->{v};++    my $size = -s $self->{fh};+    if ( $size == 0 ) {+        return 0;+    }+    elsif ( $size > 100_000 ) {+        return 1;+    }++    my $buffer;+    my $rc = sysread( $self->{fh}, $buffer, $size );+    if ( not defined $rc ) {+        App::Ack::warn( "$self->{filename}: $!" );+        return 1;+    }+    return 0 unless $rc && ( $rc == $size );++    my $regex = $opt->{regex};+    return $buffer =~ /$regex/m;+}+++sub reset {+    my $self = shift;++    seek( $self->{fh}, 0, 0 )+        or App::Ack::warn( "$self->{filename}: $!" );++    return;+}+++sub next_text {+    if ( defined ($_ = readline $_[0]->{fh}) ) {+        $. = ++$_[0]->{line};+        return 1;+    }++    return;+}+++sub close {+    my $self = shift;++    if ( not close $self->{fh} ) {+        App::Ack::warn( $self->name() . ": $!" );+    }++    return;+}++package App::Ack::Repository::Basic;+++our @ISA = qw( App::Ack::Repository );+++use warnings;+use strict;++sub new {+    my $class    = shift;+    my $filename = shift;++    my $self = bless {+        filename => $filename,+        nexted   => 0,+    }, $class;++    return $self;+}+++sub next_resource {+    my $self = shift;++    return if $self->{nexted};+    $self->{nexted} = 1;++    return App::Ack::Resource::Basic->new( $self->{filename} );+}+++sub close {+}++++1;