diff -Nru silversearcher-ag-0.22.0/ag.bashcomp.sh silversearcher-ag-0.26.0/ag.bashcomp.sh --- silversearcher-ag-0.22.0/ag.bashcomp.sh 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/ag.bashcomp.sh 2014-10-24 20:50:41.000000000 +0000 @@ -62,6 +62,7 @@ --stats --unrestricted --version + --vimgrep --word-regexp --workers ' @@ -74,6 +75,8 @@ -w -z ' + types=$(ag --list-file-types |grep -- '--') + # these options require an argument if [[ "${prev}" == -@(A|B|C|G|g|m) ]] ; then return 0 @@ -100,13 +103,8 @@ case "${cur}" in -*) - if [[ "${COMP_CWORD}" -eq 1 ]] ; then - COMPREPLY=( $(compgen -W \ - "${lngopt} ${shtopt}" -- "${cur}") ) - else - COMPREPLY=( $(compgen -W \ - "${lngopt} ${shtopt}" -- "${cur}") ) - fi + COMPREPLY=( $(compgen -W \ + "${lngopt} ${shtopt} ${types}" -- "${cur}") ) return 0;; *) _filedir diff -Nru silversearcher-ag-0.22.0/build.sh silversearcher-ag-0.26.0/build.sh --- silversearcher-ag-0.22.0/build.sh 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/build.sh 2014-10-24 20:50:41.000000000 +0000 @@ -18,4 +18,4 @@ autoheader && \ automake --add-missing && \ ./configure "$@" && \ -make +make -j4 diff -Nru silversearcher-ag-0.22.0/configure.ac silversearcher-ag-0.26.0/configure.ac --- silversearcher-ag-0.22.0/configure.ac 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/configure.ac 2014-10-24 20:50:41.000000000 +0000 @@ -1,6 +1,6 @@ AC_INIT( [the_silver_searcher], - [0.22.0], + [0.26.0], [https://github.com/ggreer/the_silver_searcher/issues], [the_silver_searcher], [https://github.com/ggreer/the_silver_searcher]) @@ -17,11 +17,16 @@ PKG_CHECK_MODULES([PCRE], [libpcre]) -# Run CFLAGS="-g" ./configure if you want debug symbols -CFLAGS="$CFLAGS $PCRE_CFLAGS -Wall -Wextra -Wformat=2 -Wno-format-nonliteral -Wshadow -Wpointer-arith -Wcast-qual -Wmissing-prototypes -Wno-missing-braces -std=gnu89 -D_GNU_SOURCE -O2" +m4_include([m4/ax_pthread.m4]) +AX_PTHREAD([ + AC_CHECK_HEADERS([pthread.h]) +]) + +# Run CFLAGS="-pg" ./configure if you want debug symbols +CFLAGS="$CFLAGS $PTHREAD_CFLAGS $PCRE_CFLAGS -Wall -Wextra -Wformat=2 -Wno-format-nonliteral -Wshadow -Wpointer-arith -Wcast-qual -Wmissing-prototypes -Wno-missing-braces -std=gnu89 -D_GNU_SOURCE -O2" LDFLAGS="$LDFLAGS" -AC_CHECK_HEADERS([pthread.h]) +LIBS="$PTHREAD_LIBS $LIBS" AC_ARG_ENABLE([zlib], AS_HELP_STRING([--disable-zlib], [Disable zlib compressed search support])) @@ -43,7 +48,7 @@ AC_CHECK_MEMBER([struct dirent.d_type], [AC_DEFINE([HAVE_DIRENT_DTYPE], [], [Have dirent struct member d_type])], [], [[#include ]]) -AC_CHECK_FUNCS(fgetln getline realpath strndup vasprintf) +AC_CHECK_FUNCS(fgetln getline realpath strlcpy strndup vasprintf madvise posix_fadvise) AC_CONFIG_FILES([Makefile the_silver_searcher.spec]) AC_CONFIG_HEADERS([src/config.h]) diff -Nru silversearcher-ag-0.22.0/debian/changelog silversearcher-ag-0.26.0/debian/changelog --- silversearcher-ag-0.22.0/debian/changelog 2014-08-22 20:14:11.000000000 +0000 +++ silversearcher-ag-0.26.0/debian/changelog 2014-10-28 19:06:20.000000000 +0000 @@ -1,8 +1,25 @@ -silversearcher-ag (0.22.0-1~andre1) trusty; urgency=medium +silversearcher-ag (0.26.0-1~andre1) trusty; urgency=medium * Backport from Ubuntu / Debian without changes - -- Andre Klitzing Fri, 22 Aug 2014 22:14:11 +0200 + -- Andre Klitzing Tue, 28 Oct 2014 20:06:20 +0100 + +silversearcher-ag (0.26.0-1) unstable; urgency=medium + + * new upstream release + * debian/control + - set Standards-Version: 3.9.6. + + -- Hajime Mizuno Sun, 26 Oct 2014 13:11:51 +0900 + +silversearcher-ag (0.24.1-1) unstable; urgency=medium + + * new upstream release + * debian/control + - Fixed typo in alternative. (Closes: #759695) + * add debian/watch + + -- Hajime Mizuno Tue, 16 Sep 2014 20:39:54 +0900 silversearcher-ag (0.22.0-1) unstable; urgency=medium diff -Nru silversearcher-ag-0.22.0/debian/control silversearcher-ag-0.26.0/debian/control --- silversearcher-ag-0.22.0/debian/control 2014-06-15 05:07:52.000000000 +0000 +++ silversearcher-ag-0.26.0/debian/control 2014-10-26 04:45:11.000000000 +0000 @@ -3,13 +3,13 @@ Priority: extra Maintainer: Hajime Mizuno Build-Depends: debhelper (>= 9.0.0), dh-autoreconf, pkg-config, libpcre3-dev, zlib1g-dev, liblzma-dev -Standards-Version: 3.9.5 +Standards-Version: 3.9.6 Homepage: https://github.com/ggreer/the_silver_searcher Package: silversearcher-ag Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} -Description: very fast grep-like program, altenative to ack-grep +Description: very fast grep-like program, alternative to ack-grep The Silver Searcher is grep-like program implemented by C. An attempt to make something better than ack-grep. . diff -Nru silversearcher-ag-0.22.0/debian/watch silversearcher-ag-0.26.0/debian/watch --- silversearcher-ag-0.22.0/debian/watch 1970-01-01 00:00:00.000000000 +0000 +++ silversearcher-ag-0.26.0/debian/watch 2014-10-26 04:11:31.000000000 +0000 @@ -0,0 +1,2 @@ +version=3 +https://github.com/ggreer/the_silver_searcher/releases /ggreer/the_silver_searcher/archive/(.+)\.tar\.gz diff -Nru silversearcher-ag-0.22.0/doc/ag.1 silversearcher-ag-0.26.0/doc/ag.1 --- silversearcher-ag-0.22.0/doc/ag.1 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/doc/ag.1 2014-10-24 20:50:41.000000000 +0000 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "AG" "1" "January 2014" "" "" +.TH "AG" "1" "August 2014" "" "" . .SH "NAME" \fBag\fR \- The Silver Searcher\. Like ack, but faster\. @@ -112,9 +112,12 @@ \~\~\~\~ Only search filenames matching PATTERN\. . .P -\fB\-\-[no]heading\fR +\fB\-H\fR, \fB\-\-[no]heading\fR: . .br +\~\~\~\~ Print file names above matching contents\. +. +.P \fB\-\-hidden\fR: . .br @@ -187,6 +190,12 @@ \~\~\~\~ Print matches on very long lines (> 2k characters by default) . .P +\fB\-\-passthrough\fR: +. +.br +\~\~\~\~ When searching a stream, print all lines even if they don\'t match\. +. +.P \fB\-Q \-\-literal\fR: . .br @@ -196,13 +205,13 @@ \fB\-s \-\-case\-sensitive\fR: . .br -\~\~\~\~ Match case sensitively\. Enabled by default\. +\~\~\~\~ Match case sensitively\. . .P \fB\-S \-\-smart\-case\fR: . .br -\~\~\~\~ Match case sensitively if there are any uppercase letters in PATTERN, or case insensitively otherwise\. +\~\~\~\~ Match case sensitively if there are any uppercase letters in PATTERN, or case insensitively otherwise\. Enabled by default\. . .P \fB\-\-search\-binary\fR: @@ -238,22 +247,44 @@ \fB\-U \-\-skip\-vcs\-ignores\fR: . .br -\~\~\~\~ Ignore VCS ignore files (\.gitigore, \.hgignore, svn:ignore), but still use \.agignore\. +\~\~\~\~ Ignore VCS ignore files (\.gitignore, \.hgignore, svn:ignore), but still use \.agignore\. . .P \fB\-v \-\-invert\-match\fR . +.P +\fB\-\-vimgrep\fR: +. .br +\~\~\~\~ Output results like vim's :vimgrep /pattern/g would (it reports every match on the line)\. +.br +\~\~\~\~ Here's a ~/.vimrc configuration example: +.P +\~\~\~\~\~\~\~\~ set grepprg=ag\\\ --vimgrep\\\ $* +.br +\~\~\~\~\~\~\~\~ set grepformat=%f:%l:%c:%m +.P +\~\~\~\~ Then use :grep to grep for something\. +.br +\~\~\~\~ Then use :copen :cn :cp etc.. to navigate through the matches\. +. +.P \fB\-w \-\-word\-regexp\fR: . .br \~\~\~\~ Only match whole words\. . +.P +\fB\-z \-\-search\-zip\fR: +. +.br +\~\~\~\~ Search contents of compressed files\. +. .SH "FILE TYPES" It is possible to restrict the types of files searched\. For example, passing \fB\-\-html\fR as the \fBfile\-types\fR parameter will search only files with the extensions \fBhtm\fR, \fBhtml\fR, \fBshtml\fR or \fBxhtml\fR\. For a list of supported \fBfile\-types\fR run \fBag \-\-list\-file\-types\fR\. . .SH "IGNORING FILES" -By default, ag will ignore files matched by patterns in \.gitignore, \.hgignore, or \.agignore\. These files can be anywhere in the directories being searched\. Ag also ignores files matched by the svn:ignore property in subversion repositories\. Finally, ag looks in $HOME/\.agignore for ignore patterns\. Binary files are ignored by default as well\. +By default, ag will ignore files matched by patterns in \.gitignore, \.hgignore, or \.agignore\. These files can be anywhere in the directories being searched\. Ag also ignores files matched by the svn:ignore property if \fBsvn \-\-version\fR is 1\.6 or older\. Finally, ag looks in $HOME/\.agignore for ignore patterns\. Binary files are ignored by default as well\. . .P If you want to ignore \.gitignore, \.hgignore, and svn:ignore but still take \.agignore into account, use \fB\-U\fR\. diff -Nru silversearcher-ag-0.22.0/doc/ag.1.md silversearcher-ag-0.26.0/doc/ag.1.md --- silversearcher-ag-0.22.0/doc/ag.1.md 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/doc/ag.1.md 2014-10-24 20:50:41.000000000 +0000 @@ -44,7 +44,8 @@ Print filenames matching PATTERN. * `-G`, `--file-search-regex PATTERN`: Only search filenames matching PATTERN. - * `--[no]heading` + * `-H`, `--[no]heading`: + Print file names above matching contents. * `--hidden`: Search hidden files. This option obeys ignore files. * `--ignore PATTERN`: @@ -61,20 +62,24 @@ See `FILE TYPES` below. * `-m --max-count NUM`: Skip the rest of a file after NUM matches. Default is 10,000. - * `--no-numbers`: + * `--no-numbers`: Don't show line numbers + * `--null`: + Separate files output with -l or -L by \0 rather than \n, this allows 'xargs -0 ' to correctly process filenames with spaces. * `-p --path-to-agignore STRING`: Provide a path to a specific .agignore file. * `--pager COMMAND`: Use a pager such as less. Use `--nopager` to override. This option is also ignored if output is piped to another program. * `--print-long-lines`: Print matches on very long lines (> 2k characters by default) + * `--passthrough`: + When searching a stream, print all lines even if they don't match. * `-Q --literal`: Do not parse PATTERN as a regular expression. Try to match it literally. * `-s --case-sensitive`: - Match case sensitively. Enabled by default. + Match case sensitively. * `-S --smart-case`: - Match case sensitively if there are any uppercase letters in PATTERN, or case insensitively otherwise. + Match case sensitively if there are any uppercase letters in PATTERN, or case insensitively otherwise. Enabled by default. * `--search-binary`: Search binary files for matches. * `--silent`: @@ -86,10 +91,19 @@ * `-u --unrestricted`: Search *all* files. This ignores .agignore, .gitignore, etc. It searches binary and hidden files as well. * `-U --skip-vcs-ignores`: - Ignore VCS ignore files (.gitigore, .hgignore, svn:ignore), but still use .agignore. + Ignore VCS ignore files (.gitignore, .hgignore, svn:ignore), but still use .agignore. * `-v --invert-match` + * `--vimgrep`: + Output results like vim's :vimgrep /pattern/g would (it reports every match on the line). + Here's a ~/.vimrc configuration example: + set grepprg=ag\ --vimgrep\ $* + set grepformat=%f:%l:%c:%m + Then use :grep to grep for something. + Then use :copen :cn :cp etc.. to navigate through the matches. * `-w --word-regexp`: Only match whole words. + * `-z --search-zip`: + Search contents of compressed files. ## FILE TYPES @@ -97,7 +111,11 @@ ## IGNORING FILES -By default, ag will ignore files matched by patterns in .gitignore, .hgignore, or .agignore. These files can be anywhere in the directories being searched. Ag also ignores files matched by the svn:ignore property in subversion repositories. Finally, ag looks in $HOME/.agignore for ignore patterns. Binary files are ignored by default as well. +By default, ag will ignore files matched by patterns in .gitignore, .hgignore, +or .agignore. These files can be anywhere in the directories being searched. Ag +also ignores files matched by the svn:ignore property if `svn --version` is 1.6 +or older. Finally, ag looks in $HOME/.agignore for +ignore patterns. Binary files are ignored by default as well. If you want to ignore .gitignore, .hgignore, and svn:ignore but still take .agignore into account, use `-U`. diff -Nru silversearcher-ag-0.22.0/.gitignore silversearcher-ag-0.26.0/.gitignore --- silversearcher-ag-0.22.0/.gitignore 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/.gitignore 2014-10-24 20:50:41.000000000 +0000 @@ -11,8 +11,10 @@ callgrind.out.* clang_output_* compile +config.guess config.log config.status +config.sub configure depcomp gmon.out @@ -23,4 +25,6 @@ src/config.h* stamp-h1 tests/*.err +tests/big/*.err +tests/big/big_file.txt the_silver_searcher.spec \ No newline at end of file diff -Nru silversearcher-ag-0.22.0/m4/ax_pthread.m4 silversearcher-ag-0.26.0/m4/ax_pthread.m4 --- silversearcher-ag-0.22.0/m4/ax_pthread.m4 1970-01-01 00:00:00.000000000 +0000 +++ silversearcher-ag-0.26.0/m4/ax_pthread.m4 2014-10-24 20:50:41.000000000 +0000 @@ -0,0 +1,332 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_pthread.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +# +# DESCRIPTION +# +# This macro figures out how to build C programs using POSIX threads. It +# sets the PTHREAD_LIBS output variable to the threads library and linker +# flags, and the PTHREAD_CFLAGS output variable to any special C compiler +# flags that are needed. (The user can also force certain compiler +# flags/libs to be tested by setting these environment variables.) +# +# Also sets PTHREAD_CC to any special C compiler that is needed for +# multi-threaded programs (defaults to the value of CC otherwise). (This +# is necessary on AIX to use the special cc_r compiler alias.) +# +# NOTE: You are assumed to not only compile your program with these flags, +# but also link it with them as well. e.g. you should link with +# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS +# +# If you are only building threads programs, you may wish to use these +# variables in your default LIBS, CFLAGS, and CC: +# +# LIBS="$PTHREAD_LIBS $LIBS" +# CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +# CC="$PTHREAD_CC" +# +# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant +# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name +# (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +# +# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the +# PTHREAD_PRIO_INHERIT symbol is defined when compiling with +# PTHREAD_CFLAGS. +# +# ACTION-IF-FOUND is a list of shell commands to run if a threads library +# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it +# is not found. If ACTION-IF-FOUND is not specified, the default action +# will define HAVE_PTHREAD. +# +# Please let the authors know if this macro fails on any platform, or if +# you have any other suggestions or comments. This macro was based on work +# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help +# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by +# Alejandro Forero Cuervo to the autoconf macro repository. We are also +# grateful for the helpful feedback of numerous users. +# +# Updated for Autoconf 2.68 by Daniel Richard G. +# +# LICENSE +# +# Copyright (c) 2008 Steven G. Johnson +# Copyright (c) 2011 Daniel Richard G. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 21 + +AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) +AC_DEFUN([AX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_LANG_PUSH([C]) +ax_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on True64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) + AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes]) + AC_MSG_RESULT([$ax_pthread_ok]) + if test x"$ax_pthread_ok" = xno; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all, and "pthread-config" +# which is a program returning the flags for the Pth emulation library. + +ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) +# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) +# -pthreads: Solaris/gcc +# -mthreads: Mingw32/gcc, Lynx/gcc +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads too; +# also defines -D_REENTRANT) +# ... -mt is also the pthreads flag for HP/aCC +# pthread: Linux, etcetera +# --thread-safe: KAI C++ +# pthread-config: use pthread-config program (for GNU Pth library) + +case ${host_os} in + solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthreads/-mt/ + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + + ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" + ;; + + darwin*) + ax_pthread_flags="-pthread $ax_pthread_flags" + ;; +esac + +# Clang doesn't consider unrecognized options an error unless we specify +# -Werror. We throw in some extra Clang-specific options to ensure that +# this doesn't happen for GCC, which also accepts -Werror. + +AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags]) +save_CFLAGS="$CFLAGS" +ax_pthread_extra_flags="-Werror" +CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument" +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])], + [AC_MSG_RESULT([yes])], + [ax_pthread_extra_flags= + AC_MSG_RESULT([no])]) +CFLAGS="$save_CFLAGS" + +if test x"$ax_pthread_ok" = xno; then +for flag in $ax_pthread_flags; do + + case $flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $flag]) + PTHREAD_CFLAGS="$flag" + ;; + + pthread-config) + AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) + if test x"$ax_pthread_config" = xno; then continue; fi + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$flag]) + PTHREAD_LIBS="-l$flag" + ;; + esac + + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include + static void routine(void *a) { a = 0; } + static void *start_routine(void *a) { return a; }], + [pthread_t th; pthread_attr_t attr; + pthread_create(&th, 0, start_routine, 0); + pthread_join(th, 0); + pthread_attr_init(&attr); + pthread_cleanup_push(routine, 0); + pthread_cleanup_pop(0) /* ; */])], + [ax_pthread_ok=yes], + []) + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + AC_MSG_RESULT([$ax_pthread_ok]) + if test "x$ax_pthread_ok" = xyes; then + break; + fi + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$ax_pthread_ok" = xyes; then + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + AC_MSG_CHECKING([for joinable pthread attribute]) + attr_name=unknown + for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], + [int attr = $attr; return attr /* ; */])], + [attr_name=$attr; break], + []) + done + AC_MSG_RESULT([$attr_name]) + if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then + AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name], + [Define to necessary symbol if this constant + uses a non-standard name on your system.]) + fi + + AC_MSG_CHECKING([if more special flags are required for pthreads]) + flag=no + case ${host_os} in + aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; + osf* | hpux*) flag="-D_REENTRANT";; + solaris*) + if test "$GCC" = "yes"; then + flag="-D_REENTRANT" + else + # TODO: What about Clang on Solaris? + flag="-mt -D_REENTRANT" + fi + ;; + esac + AC_MSG_RESULT([$flag]) + if test "x$flag" != xno; then + PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" + fi + + AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], + [ax_cv_PTHREAD_PRIO_INHERIT], [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[int i = PTHREAD_PRIO_INHERIT;]])], + [ax_cv_PTHREAD_PRIO_INHERIT=yes], + [ax_cv_PTHREAD_PRIO_INHERIT=no]) + ]) + AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], + [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])]) + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + # More AIX lossage: compile with *_r variant + if test "x$GCC" != xyes; then + case $host_os in + aix*) + AS_CASE(["x/$CC"], + [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], + [#handle absolute path differently from PATH based program lookup + AS_CASE(["x$CC"], + [x/*], + [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], + [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) + ;; + esac + fi +fi + +test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" + +AC_SUBST([PTHREAD_LIBS]) +AC_SUBST([PTHREAD_CFLAGS]) +AC_SUBST([PTHREAD_CC]) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test x"$ax_pthread_ok" = xyes; then + ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) + : +else + ax_pthread_ok=no + $2 +fi +AC_LANG_POP +])dnl AX_PTHREAD diff -Nru silversearcher-ag-0.22.0/Makefile.am silversearcher-ag-0.26.0/Makefile.am --- silversearcher-ag-0.22.0/Makefile.am 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/Makefile.am 2014-10-24 20:50:41.000000000 +0000 @@ -2,19 +2,19 @@ bin_PROGRAMS = ag ag_SOURCES = src/ignore.c src/ignore.h src/log.c src/log.h src/options.c src/options.h src/print.c src/print.h src/scandir.c src/scandir.h src/search.c src/search.h src/lang.c src/lang.h src/util.c src/util.h src/decompress.c src/decompress.h src/uthash.h src/main.c -ag_LDADD = ${PCRE_LIBS} ${LZMA_LIBS} ${ZLIB_LIBS} -lpthread +ag_LDADD = ${PCRE_LIBS} ${LZMA_LIBS} ${ZLIB_LIBS} $(PTHREAD_LIBS) dist_man_MANS = doc/ag.1 bashcompdir = $(pkgdatadir)/completions dist_bashcomp_DATA = ag.bashcomp.sh -# Uncomment this line to output gprof profiling info. This hurts performance. -#CFLAGS=-pg - EXTRA_DIST = Makefile.w32 LICENSE NOTICE the_silver_searcher.spec README.md test: cram -v tests/*.t +test_big: + cram -v tests/big/*.t + .PHONY : all test clean diff -Nru silversearcher-ag-0.22.0/Makefile.w32 silversearcher-ag-0.26.0/Makefile.w32 --- silversearcher-ag-0.22.0/Makefile.w32 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/Makefile.w32 2014-10-24 20:50:41.000000000 +0000 @@ -1,5 +1,7 @@ VERSION=$(shell grep -Po "(?<=\[)([0-9.]+.[0-9]+.[0-9]+)(?=\])" configure.ac) +CC=gcc + SRCS = \ src/decompress.c \ src/ignore.c \ @@ -20,10 +22,10 @@ all : $(TARGET) $(TARGET) : $(OBJS) - gcc -o $@ $(OBJS) $(LIBS) + $(CC) -o $@ $(OBJS) $(LIBS) .c.o : - gcc -c $(CFLAGS) -Isrc $< -o $@ + $(CC) -c $(CFLAGS) -Isrc $< -o $@ clean : rm -f src/*.o $(TARGET) diff -Nru silversearcher-ag-0.22.0/README.md silversearcher-ag-0.26.0/README.md --- silversearcher-ag-0.22.0/README.md 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/README.md 2014-10-24 20:50:41.000000000 +0000 @@ -2,6 +2,8 @@ A code searching tool similar to `ack`, with a focus on speed. +[![Build Status](https://travis-ci.org/ggreer/the_silver_searcher.svg?branch=master)](https://travis-ci.org/ggreer/the_silver_searcher) + Floobits status @@ -83,25 +85,20 @@ * Ubuntu: apt-get install -y automake pkg-config libpcre3-dev zlib1g-dev liblzma-dev - * Fedora: yum -y install pkgconfig automake gcc zlib-devel pcre-devel xz-devel - * CentOS: yum -y groupinstall "Development Tools" yum -y install pcre-devel xz-devel - * OS X: brew install automake pkg-config pcre or port install automake pkgconfig pcre - * Windows: It's complicated. See [this wiki page](https://github.com/ggreer/the_silver_searcher/wiki/Windows). - 2. Run the build script (which just runs aclocal, automake, etc): ./build.sh @@ -109,7 +106,6 @@ On Windows: mingw32-make -f Makefile.w32 - 3. Make install: sudo make install @@ -137,6 +133,12 @@ let g:ackprg = 'ag --nogroup --nocolor --column' +or: + + let g:ackprg = 'ag --vimgrep' + +Which has the same effect but will report every match on the line. + There's also a fork of ack.vim tailored for use with Ag: [ag.vim][] [ack.vim]: https://github.com/mileszs/ack.vim [ag.vim]: https://github.com/rking/ag.vim diff -Nru silversearcher-ag-0.22.0/src/ignore.c silversearcher-ag-0.26.0/src/ignore.c --- silversearcher-ag-0.22.0/src/ignore.c 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/src/ignore.c 2014-10-24 20:50:41.000000000 +0000 @@ -37,13 +37,30 @@ NULL }; -ignores *init_ignore(ignores *parent) { +ignores *init_ignore(ignores *parent, const char *dirname, const size_t dirname_len) { ignores *ig = ag_malloc(sizeof(ignores)); ig->names = NULL; ig->names_len = 0; + ig->slash_names = NULL; + ig->slash_names_len = 0; ig->regexes = NULL; ig->regexes_len = 0; + ig->slash_regexes = NULL; + ig->slash_regexes_len = 0; ig->parent = parent; + ig->dirname = dirname; + ig->dirname_len = dirname_len; + if (parent && parent->abs_path_len > 0) { + ag_asprintf(&(ig->abs_path), "%s/%s", parent->abs_path, dirname); + ig->abs_path_len = parent->abs_path_len + 1 + dirname_len; + } else if (dirname_len == 1 && dirname[0] == '.') { + ig->abs_path = ag_malloc(sizeof(char)); + ig->abs_path[0] = '\0'; + ig->abs_path_len = 0; + } else { + ag_asprintf(&(ig->abs_path), "%s", dirname); + ig->abs_path_len = dirname_len; + } return ig; } @@ -63,6 +80,9 @@ } free(ig->names); } + if (ig->abs_path) { + free(ig->abs_path); + } free(ig); } } @@ -88,29 +108,45 @@ return; } - /* TODO: de-dupe these patterns */ + char ***patterns_p; + size_t *patterns_len; if (is_fnmatch(pattern)) { - ig->regexes_len++; - ig->regexes = ag_realloc(ig->regexes, ig->regexes_len * sizeof(char *)); - if (pattern[0] != '/') { - ag_asprintf(&(ig->regexes[ig->regexes_len - 1]), "*/%s", pattern); + if (pattern[0] == '/') { + patterns_p = &(ig->slash_regexes); + patterns_len = &(ig->slash_regexes_len); + pattern++; + pattern_len--; } else { - ig->regexes[ig->regexes_len - 1] = ag_strndup(pattern, pattern_len); + patterns_p = &(ig->regexes); + patterns_len = &(ig->regexes_len); } - log_debug("added regex ignore pattern %s", pattern); } else { - /* a balanced binary tree is best for performance, but I'm lazy */ - ig->names_len++; - ig->names = ag_realloc(ig->names, ig->names_len * sizeof(char *)); - for (i = ig->names_len - 1; i > 0; i--) { - if (strcmp(pattern, ig->names[i - 1]) > 0) { - break; - } - ig->names[i] = ig->names[i - 1]; + if (pattern[0] == '/') { + patterns_p = &(ig->slash_names); + patterns_len = &(ig->slash_names_len); + pattern++; + pattern_len--; + } else { + patterns_p = &(ig->names); + patterns_len = &(ig->names_len); + } + } + + ++*patterns_len; + + char **patterns; + + /* a balanced binary tree is best for performance, but I'm lazy */ + *patterns_p = patterns = ag_realloc(*patterns_p, (*patterns_len) * sizeof(char *)); + /* TODO: de-dupe these patterns */ + for (i = *patterns_len - 1; i > 0; i--) { + if (strcmp(pattern, patterns[i - 1]) > 0) { + break; } - ig->names[i] = ag_strndup(pattern, pattern_len); - log_debug("added literal ignore pattern %s", pattern); + patterns[i] = patterns[i - 1]; } + patterns[i] = ag_strndup(pattern, pattern_len); + log_debug("added ignore pattern %s to %s", pattern, ig->abs_path); } /* For loading git/hg ignore patterns */ @@ -218,7 +254,10 @@ return pcre_exec(opts.ackmate_dir_filter, NULL, dir_name, strlen(dir_name), 0, 0, NULL, 0); } -static int filename_ignore_search(const ignores *ig, const char *filename) { +static int path_ignore_search(const ignores *ig, const char *path, const char *filename) { + char *temp; + + size_t i; int match_pos; if (strncmp(filename, "./", 2) == 0) { @@ -231,42 +270,63 @@ return 1; } - log_debug("file %s not ignored", filename); - return 0; -} - -static int path_ignore_search(const ignores *ig, const char *path, const char *filename) { - char *temp; - - if (filename_ignore_search(ig, filename)) { - return 1; - } - ag_asprintf(&temp, "%s/%s", path[0] == '.' ? path + 1 : path, filename); + log_debug("temp: %s abs path: %s", temp, ig->abs_path); - if (filename_ignore_search(ig, temp)) { - free(temp); - return 1; + if (strncmp(temp, ig->abs_path, ig->abs_path_len) == 0) { + char *slash_filename = temp + ig->abs_path_len; + if (slash_filename[0] == '/') { + slash_filename++; + } + match_pos = binary_search(slash_filename, ig->names, 0, ig->names_len); + if (match_pos >= 0) { + log_debug("file %s ignored because name matches static pattern %s", temp, ig->names[match_pos]); + free(temp); + return 1; + } + + match_pos = binary_search(slash_filename, ig->slash_names, 0, ig->slash_names_len); + if (match_pos >= 0) { + log_debug("file %s ignored because name matches slash static pattern %s", slash_filename, ig->slash_names[match_pos]); + free(temp); + return 1; + } + + for (i = 0; i < ig->names_len; i++) { + char *pos = strstr(slash_filename, ig->names[i]); + if (pos == slash_filename || (pos && *(pos - 1) == '/')) { + pos += strlen(ig->names[i]); + if (*pos == '\0' || *pos == '/') { + log_debug("file %s ignored because path somewhere matches name %s", slash_filename, ig->names[i]); + free(temp); + return 1; + } + } + log_debug("pattern %s doesn't match name %s", slash_filename, ig->names[i]); + } + + for (i = 0; i < ig->slash_regexes_len; i++) { + if (fnmatch(ig->slash_regexes[i], slash_filename, fnmatch_flags) == 0) { + log_debug("file %s ignored because name matches slash regex pattern %s", slash_filename, ig->slash_regexes[i]); + free(temp); + return 1; + } + log_debug("pattern %s doesn't match slash file %s", ig->slash_regexes[i], slash_filename); + } } - int rv = 0; - size_t i; - char *regex; for (i = 0; i < ig->regexes_len; i++) { - regex = ig->regexes[i]; - /* TODO: behave specially if regex doesn't start with a slash - if (regex[0] == '/') { - */ - if (fnmatch(regex, temp, fnmatch_flags) == 0) { - log_debug("file %s ignored because name matches regex pattern %s", temp, regex); - rv = 1; - break; + if (fnmatch(ig->regexes[i], filename, fnmatch_flags) == 0) { + log_debug("file %s ignored because name matches regex pattern %s", filename, ig->regexes[i]); + free(temp); + return 1; } - log_debug("pattern %s doesn't match file %s", regex, temp); - } - if (rv == 0) { - rv = ackmate_dir_match(temp); + log_debug("pattern %s doesn't match file %s", ig->regexes[i], filename); } + + log_debug("file %s not ignored", filename); + + int rv = ackmate_dir_match(temp); free(temp); return rv; } diff -Nru silversearcher-ag-0.22.0/src/ignore.h silversearcher-ag-0.26.0/src/ignore.h --- silversearcher-ag-0.22.0/src/ignore.h 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/src/ignore.h 2014-10-24 20:50:41.000000000 +0000 @@ -11,8 +11,19 @@ struct ignores { char **names; /* Non-regex ignore lines. Sorted so we can binary search them. */ size_t names_len; + char **slash_names; /* Same but starts with a slash */ + size_t slash_names_len; + char **regexes; /* For patterns that need fnmatch */ size_t regexes_len; + char **slash_regexes; + size_t slash_regexes_len; + + const char *dirname; + size_t dirname_len; + char *abs_path; + size_t abs_path_len; + struct ignores *parent; }; typedef struct ignores ignores; @@ -22,7 +33,7 @@ extern const char *evil_hardcoded_ignore_files[]; extern const char *ignore_pattern_files[]; -ignores *init_ignore(ignores *parent); +ignores *init_ignore(ignores *parent, const char *dirname, const size_t dirname_len); void cleanup_ignore(ignores *ig); void add_ignore_pattern(ignores *ig, const char *pattern); diff -Nru silversearcher-ag-0.22.0/src/lang.c silversearcher-ag-0.26.0/src/lang.c --- silversearcher-ag-0.22.0/src/lang.c 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/src/lang.c 2014-10-24 20:50:41.000000000 +0000 @@ -11,31 +11,35 @@ { "batch", { "bat", "cmd" } }, { "cc", { "c", "h", "xs" } }, { "cfmx", { "cfc", "cfm", "cfml" } }, - { "clojure", { "clj" } }, + { "clojure", { "clj", "cljs", "cljx" } }, { "coffee", { "coffee" } }, - { "cpp", { "cpp", "cc", "cxx", "m", "hpp", "hh", "h", "hxx" } }, + { "cpp", { "cpp", "cc", "C", "cxx", "m", "hpp", "hh", "h", "H", "hxx" } }, { "csharp", { "cs" } }, { "css", { "css" } }, { "delphi", { "pas", "int", "dfm", "nfm", "dof", "dpk", "dproj", "groupproj", "bdsgroup", "bdsproj" } }, { "elisp", { "el" } }, { "erlang", { "erl", "hrl" } }, { "fortran", { "f", "f77", "f90", "f95", "f03", "for", "ftn", "fpp" } }, + { "gettext", { "po", "pot", "mo" } }, { "go", { "go" } }, { "groovy", { "groovy", "gtmpl", "gpp", "grunit" } }, + { "haml", { "haml" } }, { "haskell", { "hs", "lhs" } }, { "hh", { "h" } }, - { "haml", { "haml" } }, { "html", { "htm", "html", "shtml", "xhtml" } }, + { "ini", { "ini" } }, + { "jade", { "jade" } }, { "java", { "java", "properties" } }, { "js", { "js" } }, - { "jsp", { "jsp", "jspx", "jhtm", "jhtml" } }, { "json", { "json" } }, + { "jsp", { "jsp", "jspx", "jhtm", "jhtml" } }, + { "less", { "less" } }, { "lisp", { "lisp", "lsp" } }, { "lua", { "lua" } }, { "m4", { "m4" } }, - { "matlab", { "m" } }, { "make", { "Makefiles", "mk", "mak" } }, { "mason", { "mas", "mhtml", "mpl", "mtxt" } }, + { "matlab", { "m" } }, { "objc", { "m", "h" } }, { "objcpp", { "mm", "h" } }, { "ocaml", { "ml", "mli" } }, @@ -49,13 +53,15 @@ { "rs", { "rs" } }, { "ruby", { "rb", "rhtml", "rjs", "rxml", "erb", "rake", "spec" } }, { "rust", { "rs" } }, - { "sass", { "sass", "scss" } }, { "salt", { "sls" } }, + { "sass", { "sass", "scss" } }, { "scala", { "scala" } }, { "scheme", { "scm", "ss" } }, { "shell", { "sh", "bash", "csh", "tcsh", "ksh", "zsh" } }, { "smalltalk", { "st" } }, { "sql", { "sql", "ctl" } }, + { "stylus", { "styl" } }, + { "swift", { "swift" } }, { "tcl", { "tcl", "itcl", "itk" } }, { "tex", { "tex", "cls", "sty" } }, { "tt", { "tt", "tt2", "ttml" } }, @@ -63,11 +69,14 @@ { "verilog", { "v", "vh", "sv" } }, { "vhdl", { "vhd", "vhdl" } }, { "vim", { "vim" } }, - { "yaml", { "yaml", "yml" } }, { "xml", { "xml", "dtd", "xsl", "xslt", "ent" } }, - { NULL, { NULL } } + { "yaml", { "yaml", "yml" } } }; +unsigned int get_lang_count() { + return sizeof(langs) / sizeof(lang_spec_t); +} + char *make_lang_regex(const char **extensions) { int regex_capacity = 100; char *regex = ag_malloc(regex_capacity); diff -Nru silversearcher-ag-0.22.0/src/lang.h silversearcher-ag-0.26.0/src/lang.h --- silversearcher-ag-0.22.0/src/lang.h 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/src/lang.h 2014-10-24 20:50:41.000000000 +0000 @@ -2,7 +2,6 @@ #define LANG_H #define MAX_EXTENSIONS 12 -#define LANG_COUNT 56 typedef struct { const char *name; @@ -12,6 +11,11 @@ extern lang_spec_t langs[]; /** + Return the language count. + */ +unsigned int get_lang_count(void); + +/** Convert a NULL-terminated array of language extensions into a regular expression of the form \.(extension1|extension2...)$ diff -Nru silversearcher-ag-0.22.0/src/main.c silversearcher-ag-0.26.0/src/main.c --- silversearcher-ag-0.22.0/src/main.c 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/src/main.c 2014-10-24 20:50:41.000000000 +0000 @@ -1,23 +1,25 @@ #include -#include #include #include #include #include #include #include +#ifdef _WIN32 +#include +#endif #include "config.h" +#ifdef HAVE_PTHREAD_H +#include +#endif + #include "log.h" #include "options.h" #include "search.h" #include "util.h" -#ifdef _WIN32 -#include -#endif - int main(int argc, char **argv) { char **base_paths = NULL; char **paths = NULL; @@ -33,7 +35,7 @@ work_queue = NULL; work_queue_tail = NULL; memset(&stats, 0, sizeof(stats)); - root_ignores = init_ignore(NULL); + root_ignores = init_ignore(NULL, "", 0); out_fd = stdout; #ifdef USE_PCRE_JIT int has_jit = 0; @@ -57,27 +59,35 @@ #else workers_len = (int)sysconf(_SC_NPROCESSORS_ONLN); #endif - if (opts.literal) + if (opts.literal) { workers_len--; - if (opts.workers) + } + if (opts.workers) { workers_len = opts.workers; - if (workers_len < 1) + } + if (workers_len < 1) { workers_len = 1; + } log_debug("Using %i workers", workers_len); done_adding_files = FALSE; workers = ag_calloc(workers_len, sizeof(pthread_t)); - if (pthread_cond_init(&files_ready, NULL)) + if (pthread_cond_init(&files_ready, NULL)) { die("pthread_cond_init failed!"); - if (pthread_mutex_init(&print_mtx, NULL)) + } + if (pthread_mutex_init(&print_mtx, NULL)) { die("pthread_mutex_init failed!"); - if (pthread_mutex_init(&stats_mtx, NULL)) + } + if (pthread_mutex_init(&stats_mtx, NULL)) { die("pthread_mutex_init failed!"); - if (pthread_mutex_init(&work_queue_mtx, NULL)) + } + if (pthread_mutex_init(&work_queue_mtx, NULL)) { die("pthread_mutex_init failed!"); + } - if (opts.casing == CASE_SMART) + if (opts.casing == CASE_SMART) { opts.casing = is_lowercase(opts.query) ? CASE_INSENSITIVE : CASE_SENSITIVE; + } if (opts.literal) { if (opts.casing == CASE_INSENSITIVE) { @@ -87,7 +97,9 @@ *c = (char)tolower(*c); } } - generate_skip_lookup(opts.query, opts.query_len, skip_lookup, opts.casing == CASE_SENSITIVE); + generate_alpha_skip(opts.query, opts.query_len, alpha_skip_lookup, opts.casing == CASE_SENSITIVE); + find_skip_lookup = NULL; + generate_find_skip(opts.query, opts.query_len, &find_skip_lookup, opts.casing == CASE_SENSITIVE); if (opts.word_regexp) { init_wordchar_table(); opts.literal_starts_wordchar = is_wordchar(opts.query[0]); @@ -95,7 +107,7 @@ } } else { if (opts.casing == CASE_INSENSITIVE) { - pcre_opts = pcre_opts | PCRE_CASELESS; + pcre_opts |= PCRE_CASELESS; } if (opts.word_regexp) { char *word_regexp_query; @@ -119,7 +131,9 @@ for (i = 0; paths[i] != NULL; i++) { log_debug("searching path %s for %s", paths[i], opts.query); symhash = NULL; - search_dir(root_ignores, base_paths[i], paths[i], 0); + ignores *ig = init_ignore(root_ignores, "", 0); + search_dir(ig, base_paths[i], paths[i], 0); + cleanup_ignore(ig); } pthread_mutex_lock(&work_queue_mtx); done_adding_files = TRUE; @@ -157,5 +171,8 @@ } free(base_paths); free(paths); - return 0; + if (find_skip_lookup) { + free(find_skip_lookup); + } + return !opts.match_found; } diff -Nru silversearcher-ag-0.22.0/src/options.c silversearcher-ag-0.26.0/src/options.c --- silversearcher-ag-0.22.0/src/options.c 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/src/options.c 2014-10-24 20:50:41.000000000 +0000 @@ -32,8 +32,8 @@ printf("\ Output Options:\n\ --ackmate Print results in AckMate-parseable format\n\ - -A --after [LINES] Print lines before match (Default: 2)\n\ - -B --before [LINES] Print lines after match (Default: 2)\n\ + -A --after [LINES] Print lines after match (Default: 2)\n\ + -B --before [LINES] Print lines before match (Default: 2)\n\ --[no]break Print newlines between matches in different files\n\ (Enabled by default)\n\ --[no]color Print color codes in results (Enabled by default)\n\ @@ -41,7 +41,7 @@ --color-match Color codes for result match numbers (Default: 30;43)\n\ --color-path Color codes for path names (Default: 1;32)\n\ --column Print column numbers in results\n\ - --[no]heading\n\ + -H --[no]heading Print file names (Enabled unless searching a single file)\n\ --line-numbers Print line numbers even for streams\n\ -C --context [LINES] Print lines before and after matches (Default: 2)\n\ --[no]group Same as --[no]break --[no]heading\n\ @@ -50,10 +50,15 @@ (don't print the matching lines)\n\ -L --files-without-matches\n\ Only print filenames that don't contain matches\n\ + --null Follow filename (-l|-L) with null for 'xargs -0'\n\ --no-numbers Don't print line numbers\n\ --print-long-lines Print matches on very long lines (Default: >2k characters)\n\ + --passthrough When searching a stream, print all lines even if they\n\ + don't match\n\ --silent Suppress all log messages, including errors\n\ --stats Print stats (files scanned, time taken, etc.)\n\ + --vimgrep Print results like vim's :vimgrep /pattern/g would\n\ + (it reports every match on the line)\n\ \n\ Search Options:\n\ -a --all-types Search all files (doesn't include hidden files\n\ @@ -71,9 +76,9 @@ -p --path-to-agignore STRING\n\ Use .agignore file at STRING\n\ -Q --literal Don't parse PATTERN as a regular expression\n\ - -s --case-sensitive Match case sensitively (Enabled by default)\n\ + -s --case-sensitive Match case sensitively\n\ -S --smart-case Match case insensitively unless PATTERN contains\n\ - uppercase characters\n\ + uppercase characters (Enabled by default)\n\ --search-binary Search binary files for matches\n\ -t --all-text Search all text files (doesn't include hidden files)\n\ -u --unrestricted Search all files (ignore .agignore, .gitignore, etc.;\n\ @@ -99,16 +104,16 @@ void init_options(void) { memset(&opts, 0, sizeof(opts)); - opts.casing = CASE_SENSITIVE; + opts.casing = CASE_SMART; #ifdef _WIN32 - opts.color = getenv("ANSICON") ? TRUE : FALSE; + opts.color = (getenv("ANSICON") || getenv("CMDER_ROOT")) ? TRUE : FALSE; #else opts.color = TRUE; #endif opts.max_matches_per_file = 10000; - opts.max_search_depth = 25; + opts.max_search_depth = DEFAULT_MAX_SEARCH_DEPTH; opts.print_break = TRUE; - opts.print_heading = TRUE; + opts.print_path = PATH_PRINT_DEFAULT; opts.print_line_numbers = TRUE; opts.recurse_dirs = TRUE; opts.color_path = ag_strdup(color_path); @@ -148,7 +153,7 @@ void parse_options(int argc, char **argv, char **base_paths[], char **paths[]) { int ch; - int i; + unsigned int i; int path_len = 0; int useless = 0; int group = 1; @@ -156,11 +161,14 @@ int version = 0; int list_file_types = 0; int opt_index = 0; + char *num_end; const char *home_dir = getenv("HOME"); char *ignore_file_path = NULL; + int accepts_query = 1; int needs_query = 1; struct stat statbuf; int rv; + unsigned int lang_count; size_t longopts_len, full_len; option_t *longopts; @@ -171,16 +179,16 @@ option_t base_longopts[] = { { "ackmate", no_argument, &opts.ackmate, 1 }, { "ackmate-dir-filter", required_argument, NULL, 0 }, - { "after", required_argument, NULL, 'A' }, + { "after", optional_argument, NULL, 'A' }, { "all-text", no_argument, NULL, 't' }, { "all-types", no_argument, NULL, 'a' }, - { "before", required_argument, NULL, 'B' }, + { "before", optional_argument, NULL, 'B' }, { "break", no_argument, &opts.print_break, 1 }, { "case-sensitive", no_argument, NULL, 's' }, { "color", no_argument, &opts.color, 1 }, - { "color-path", required_argument, NULL, 0 }, - { "color-match", required_argument, NULL, 0 }, { "color-line-number", required_argument, NULL, 0 }, + { "color-match", required_argument, NULL, 0 }, + { "color-path", required_argument, NULL, 0 }, { "column", no_argument, &opts.column, 1 }, { "context", optional_argument, NULL, 'C' }, { "debug", no_argument, NULL, 'D' }, @@ -190,12 +198,12 @@ { "files-without-matches", no_argument, NULL, 'L' }, { "follow", no_argument, &opts.follow_symlinks, 1 }, { "group", no_argument, &group, 1 }, - { "heading", no_argument, &opts.print_heading, 1 }, + { "heading", no_argument, &opts.print_path, PATH_PRINT_TOP }, { "help", no_argument, NULL, 'h' }, { "hidden", no_argument, &opts.search_hidden_files, 1 }, { "ignore", required_argument, NULL, 0 }, - { "ignore-dir", required_argument, NULL, 0 }, { "ignore-case", no_argument, NULL, 'i' }, + { "ignore-dir", required_argument, NULL, 0 }, { "invert-match", no_argument, &opts.invert_match, 1 }, { "line-numbers", no_argument, &opts.print_line_numbers, 2 }, { "list-file-types", no_argument, &list_file_types, 1 }, @@ -208,32 +216,37 @@ { "nocolor", no_argument, &opts.color, 0 }, { "nofollow", no_argument, &opts.follow_symlinks, 0 }, { "nogroup", no_argument, &group, 0 }, - { "noheading", no_argument, &opts.print_heading, 0 }, + { "noheading", no_argument, &opts.print_path, PATH_PRINT_EACH_LINE }, { "nopager", no_argument, NULL, 0 }, + { "null", no_argument, &opts.null_follows_filename, 1 }, { "pager", required_argument, NULL, 0 }, { "parallel", no_argument, &opts.parallel, 1 }, + { "passthrough", no_argument, &opts.passthrough, 1 }, + { "passthru", no_argument, &opts.passthrough, 1 }, { "path-to-agignore", required_argument, NULL, 'p' }, { "print-long-lines", no_argument, &opts.print_long_lines, 1 }, { "recurse", no_argument, NULL, 'r' }, { "search-binary", no_argument, &opts.search_binary_files, 1 }, - { "search-zip", no_argument, &opts.search_zip_files, 1 }, { "search-files", no_argument, &opts.search_stream, 0 }, + { "search-zip", no_argument, &opts.search_zip_files, 1 }, { "silent", no_argument, NULL, 0 }, { "skip-vcs-ignores", no_argument, NULL, 'U' }, { "smart-case", no_argument, NULL, 'S' }, { "stats", no_argument, &opts.stats, 1 }, { "unrestricted", no_argument, NULL, 'u' }, { "version", no_argument, &version, 1 }, + { "vimgrep", no_argument, &opts.vimgrep, 1 }, { "word-regexp", no_argument, NULL, 'w' }, { "workers", required_argument, NULL, 0 }, }; + lang_count = get_lang_count(); longopts_len = (sizeof(base_longopts) / sizeof(option_t)); - full_len = (longopts_len + LANG_COUNT + 1); + full_len = (longopts_len + lang_count + 1); longopts = ag_malloc(full_len * sizeof(option_t)); memcpy(longopts, base_longopts, sizeof(base_longopts)); - for (i = 0; i < LANG_COUNT; i++) { + for (i = 0; i < lang_count; i++) { option_t opt = { langs[i].name, no_argument, NULL, 0 }; longopts[i + longopts_len] = opt; } @@ -269,22 +282,40 @@ opts.stdout_inode = statbuf.st_ino; } - while ((ch = getopt_long(argc, argv, "A:aB:C:DG:g:fhiLlm:np:QRrSsvVtuUwz", longopts, &opt_index)) != -1) { + while ((ch = getopt_long(argc, argv, "A:aB:C:DG:g:fHhiLlm:np:QRrSsvVtuUwz", longopts, &opt_index)) != -1) { switch (ch) { case 'A': - opts.after = atoi(optarg); + if (optarg) { + opts.after = strtol(optarg, &num_end, 10); + if (num_end == optarg || *num_end != '\0' || errno == ERANGE) { + /* This arg must be the search string instead of the after length */ + optind--; + opts.after = DEFAULT_AFTER_LEN; + } + } else { + opts.after = DEFAULT_AFTER_LEN; + } break; case 'a': opts.search_all_files = 1; opts.search_binary_files = 1; break; case 'B': - opts.before = atoi(optarg); + if (optarg) { + opts.before = strtol(optarg, &num_end, 10); + if (num_end == optarg || *num_end != '\0' || errno == ERANGE) { + /* This arg must be the search string instead of the before length */ + optind--; + opts.before = DEFAULT_BEFORE_LEN; + } + } else { + opts.before = DEFAULT_BEFORE_LEN; + } break; case 'C': if (optarg) { - opts.context = atoi(optarg); - if (opts.context == 0 && errno == EINVAL) { + opts.context = strtol(optarg, &num_end, 10); + if (num_end == optarg || *num_end != '\0' || errno == ERANGE) { /* This arg must be the search string instead of the context length */ optind--; opts.context = DEFAULT_CONTEXT_LEN; @@ -300,13 +331,16 @@ opts.follow_symlinks = 1; break; case 'g': - needs_query = 0; + needs_query = accepts_query = 0; opts.match_files = 1; /* Fall through and build regex */ case 'G': compile_study(&opts.file_search_regex, &opts.file_search_regex_extra, optarg, opts.casing & PCRE_CASELESS, 0); opts.casing = CASE_SENSITIVE; break; + case 'H': + opts.print_path = PATH_PRINT_TOP; + break; case 'h': help = 1; break; @@ -317,6 +351,7 @@ opts.invert_match = 1; /* fall through */ case 'l': + needs_query = 0; opts.print_filename_only = 1; break; case 'm': @@ -412,7 +447,7 @@ break; } - for (i = 0; i < LANG_COUNT; i++) { + for (i = 0; i < lang_count; i++) { if (strcmp(longopts[opt_index].name, langs[i].name) == 0) { lang_regex = make_lang_regex(langs[i].extensions); compile_study(&opts.file_search_regex, &opts.file_search_regex_extra, lang_regex, 0, 0); @@ -456,9 +491,9 @@ } if (list_file_types) { - int lang_index; + unsigned int lang_index; printf("The following file types are supported:\n"); - for (lang_index = 0; lang_index < LANG_COUNT; lang_index++) { + for (lang_index = 0; lang_index < lang_count; lang_index++) { printf(" --%s\n ", langs[lang_index].name); int j; for (j = 0; j < MAX_EXTENSIONS && langs[lang_index].extensions[j]; j++) { @@ -486,7 +521,11 @@ size_t buf_len = 0; char *gitconfig_res = NULL; +#ifdef _WIN32 + gitconfig_file = popen("git config -z --get core.excludesfile 2>NUL", "r"); +#else gitconfig_file = popen("git config -z --get core.excludesfile 2>/dev/null", "r"); +#endif if (gitconfig_file != NULL) { do { gitconfig_res = ag_realloc(gitconfig_res, buf_len + 65); @@ -511,36 +550,45 @@ opts.search_stream = 0; } + if (opts.vimgrep) { + opts.color = 0; + opts.print_break = 0; + group = 1; + opts.search_stream = 0; + opts.print_path = PATH_PRINT_NOTHING; + } + if (opts.parallel) { opts.search_stream = 0; } - if (opts.print_heading == 0 || opts.print_break == 0) { + if (opts.print_path != PATH_PRINT_DEFAULT || opts.print_break == 0) { goto skip_group; } if (group) { - opts.print_heading = 1; opts.print_break = 1; } else { - opts.print_heading = 0; + opts.print_path = PATH_PRINT_DEFAULT_EACH_LINE; opts.print_break = 0; } skip_group: if (opts.search_stream) { opts.print_break = 0; - opts.print_heading = 0; + opts.print_path = PATH_PRINT_NOTHING; if (opts.print_line_numbers != 2) { opts.print_line_numbers = 0; } } - if (needs_query) { + if (accepts_query && argc > 0) { + // use the provided query opts.query = ag_strdup(argv[0]); argc--; argv++; - } else { + } else if (!needs_query) { + // use default query opts.query = ag_strdup("."); } opts.query_len = strlen(opts.query); @@ -562,7 +610,7 @@ if (argc > 0) { *paths = ag_calloc(sizeof(char *), argc + 1); *base_paths = ag_calloc(sizeof(char *), argc + 1); - for (i = 0; i < argc; i++) { + for (i = 0; i < (unsigned int)argc; i++) { path = ag_strdup(argv[i]); path_len = strlen(path); /* kill trailing slash */ diff -Nru silversearcher-ag-0.22.0/src/options.h silversearcher-ag-0.26.0/src/options.h --- silversearcher-ag-0.22.0/src/options.h 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/src/options.h 2014-10-24 20:50:41.000000000 +0000 @@ -6,8 +6,10 @@ #include +#define DEFAULT_AFTER_LEN 2 +#define DEFAULT_BEFORE_LEN 2 #define DEFAULT_CONTEXT_LEN 2 - +#define DEFAULT_MAX_SEARCH_DEPTH 25 enum case_behavior { CASE_SENSITIVE, CASE_INSENSITIVE, @@ -15,6 +17,14 @@ CASE_SENSITIVE_RETRY_INSENSITIVE /* for future use */ }; +enum path_print_behavior { + PATH_PRINT_DEFAULT, /* PRINT_TOP if > 1 file being searched, else PRINT_NOTHING */ + PATH_PRINT_DEFAULT_EACH_LINE, /* PRINT_EACH_LINE if > 1 file being searched, else PRINT_NOTHING */ + PATH_PRINT_TOP, + PATH_PRINT_EACH_LINE, + PATH_PRINT_NOTHING +}; + typedef struct { int ackmate; pcre *ackmate_dir_filter; @@ -39,12 +49,14 @@ int literal_ends_wordchar; int max_matches_per_file; int max_search_depth; + int null_follows_filename; char *path_to_agignore; int print_break; int print_filename_only; - int print_heading; + int print_path; int print_line_numbers; int print_long_lines; /* TODO: support this in print.c */ + int passthrough; pcre *re; pcre_extra *re_extra; int recurse_dirs; @@ -56,12 +68,14 @@ int search_stream; /* true if tail -F blah | ag */ int stats; size_t stream_line_num; /* This should totally not be in here */ + int match_found; /* This should totally not be in here */ ino_t stdout_inode; char *query; int query_len; char *pager; int paths_len; int parallel; + int vimgrep; int word_regexp; int workers; } cli_options; diff -Nru silversearcher-ag-0.22.0/src/print.c silversearcher-ag-0.26.0/src/print.c --- silversearcher-ag-0.22.0/src/print.c 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/src/print.c 2014-10-24 20:50:41.000000000 +0000 @@ -18,6 +18,8 @@ if (opts.ackmate) { fprintf(out_fd, ":%s%c", path, sep); + } else if (opts.vimgrep) { + fprintf(out_fd, "%s%c", path, sep); } else { if (opts.color) { fprintf(out_fd, "%s%s%s%c", opts.color_path, path, color_reset, sep); @@ -27,13 +29,19 @@ } } +void print_line(const char *buf, size_t buf_pos, size_t prev_line_offset) { + for (; prev_line_offset <= buf_pos; prev_line_offset++) { + fputc(buf[prev_line_offset], out_fd); + } +} + void print_binary_file_matches(const char *path) { path = normalize_path(path); print_file_separator(); fprintf(out_fd, "Binary file %s matches.\n", path); } -void print_file_matches(const char *path, const char *buf, const size_t buf_len, const match matches[], const size_t matches_len) { +void print_file_matches(const char *path, const char *buf, const size_t buf_len, const match_t matches[], const size_t matches_len) { size_t line = 1; char **context_prev_lines = NULL; size_t prev_line = 0; @@ -49,13 +57,19 @@ int in_a_match = FALSE; int printing_a_match = FALSE; - if (opts.ackmate) { + if (opts.ackmate || opts.vimgrep) { sep = ':'; } print_file_separator(); - if (opts.print_heading == TRUE) { + if (opts.print_path == PATH_PRINT_DEFAULT) { + opts.print_path = PATH_PRINT_TOP; + } else if (opts.print_path == PATH_PRINT_DEFAULT_EACH_LINE) { + opts.print_path = PATH_PRINT_EACH_LINE; + } + + if (opts.print_path == PATH_PRINT_TOP) { print_path(path, '\n'); } @@ -88,7 +102,7 @@ for (j = (opts.before - lines_to_print); j < opts.before; j++) { prev_line = (last_prev_line + j) % opts.before; if (context_prev_lines[prev_line] != NULL) { - if (opts.print_heading == 0) { + if (opts.print_path == PATH_PRINT_EACH_LINE) { print_path(path, ':'); } print_line_number(line - (opts.before - j), sep); @@ -112,10 +126,9 @@ if (buf[i] == '\n' || i == buf_len) { if (lines_since_last_match == 0) { - if (opts.print_heading == 0 && !opts.search_stream) { + if (opts.print_path == PATH_PRINT_EACH_LINE && !opts.search_stream) { print_path(path, ':'); } - if (opts.ackmate) { /* print headers for ackmate to parse */ print_line_number(line, ';'); @@ -125,15 +138,18 @@ (matches[last_printed_match].end - matches[last_printed_match].start)); last_printed_match == cur_match - 1 ? fputc(':', out_fd) : fputc(',', out_fd); } - j = prev_line_offset; - /* print up to current char */ - for (; j <= i; j++) { - fputc(buf[j], out_fd); + print_line(buf, i, prev_line_offset); + } else if (opts.vimgrep) { + for (; last_printed_match < cur_match; last_printed_match++) { + print_path(path, sep); + print_line_number(line, sep); + print_column_number(matches, last_printed_match, prev_line_offset, sep); + print_line(buf, i, prev_line_offset); } } else { print_line_number(line, ':'); if (opts.column) { - fprintf(out_fd, "%lu:", (matches[last_printed_match].start - prev_line_offset) + 1); + print_column_number(matches, last_printed_match, prev_line_offset, ':'); } if (printing_a_match && opts.color) { @@ -164,7 +180,7 @@ } } else if (lines_since_last_match <= opts.after) { /* print context after matching line */ - if (opts.print_heading == 0) { + if (opts.print_path == PATH_PRINT_EACH_LINE) { print_path(path, ':'); } print_line_number(line, sep); @@ -181,7 +197,7 @@ lines_since_last_match++; } /* File doesn't end with a newline. Print one so the output is pretty. */ - if (i == buf_len && buf[i] != '\n') { + if (i == buf_len && buf[i] != '\n' && !opts.search_stream) { fputc('\n', out_fd); } } @@ -209,6 +225,13 @@ } } +void print_column_number(const match_t matches[], size_t last_printed_match, + size_t prev_line_offset, const char sep) { + fprintf(out_fd, "%lu%c", + (matches[last_printed_match].start - prev_line_offset) + 1, + sep); +} + void print_file_separator(void) { if (first_file_match == 0 && opts.print_break) { fprintf(out_fd, "\n"); diff -Nru silversearcher-ag-0.22.0/src/print.h silversearcher-ag-0.26.0/src/print.h --- silversearcher-ag-0.22.0/src/print.h 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/src/print.h 2014-10-24 20:50:41.000000000 +0000 @@ -4,9 +4,12 @@ #include "util.h" void print_path(const char *path, const char sep); +void print_line(const char *buf, size_t buf_pos, size_t prev_line_offset); void print_binary_file_matches(const char *path); -void print_file_matches(const char *path, const char *buf, const size_t buf_len, const match matches[], const size_t matches_len); +void print_file_matches(const char *path, const char *buf, const size_t buf_len, const match_t matches[], const size_t matches_len); void print_line_number(size_t line, const char sep); +void print_column_number(const match_t matches[], size_t last_printed_match, + size_t prev_line_offset, const char sep); void print_file_separator(void); const char *normalize_path(const char *path); diff -Nru silversearcher-ag-0.22.0/src/search.c silversearcher-ag-0.26.0/src/search.c --- silversearcher-ag-0.22.0/src/search.c 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/src/search.c 2014-10-24 20:50:41.000000000 +0000 @@ -17,7 +17,7 @@ } int matches_len = 0; - match *matches; + match_t *matches; size_t matches_size; size_t matches_spare; @@ -28,7 +28,7 @@ * capacity for one extra. */ matches_size = 100; - matches = ag_malloc(matches_size * sizeof(match)); + matches = ag_malloc(matches_size * sizeof(match_t)); matches_spare = 1; } else { matches_size = 0; @@ -38,7 +38,7 @@ if (opts.query_len == 1 && opts.query[0] == '.') { matches_size = 1; - matches = ag_malloc(matches_size * sizeof(match)); + matches = ag_malloc(matches_size * sizeof(match_t)); matches[0].start = 0; matches[0].end = buf_len; matches_len = 1; @@ -47,7 +47,7 @@ strncmp_fp ag_strnstr_fp = get_strstr(opts.casing); while (buf_offset < buf_len) { - match_ptr = ag_strnstr_fp(match_ptr, opts.query, buf_len - buf_offset, opts.query_len, skip_lookup); + match_ptr = ag_strnstr_fp(match_ptr, opts.query, buf_len - buf_offset, opts.query_len, alpha_skip_lookup, find_skip_lookup); if (match_ptr == NULL) { break; } @@ -75,14 +75,13 @@ if ((size_t)matches_len + matches_spare >= matches_size) { /* TODO: benchmark initial size of matches. 100 may be too small/big */ matches_size = matches ? matches_size * 2 : 100; - log_debug("Too many matches in %s. Reallocating matches to %zu.", dir_full_path, matches_size); - matches = ag_realloc(matches, matches_size * sizeof(match)); + matches = ag_realloc(matches, matches_size * sizeof(match_t)); } matches[matches_len].start = match_ptr - buf; matches[matches_len].end = matches[matches_len].start + opts.query_len; buf_offset = matches[matches_len].end; - log_debug("Match found. File %s, offset %i bytes.", dir_full_path, matches[matches_len].start); + log_debug("Match found. File %s, offset %lu bytes.", dir_full_path, matches[matches_len].start); matches_len++; match_ptr += opts.query_len; @@ -101,8 +100,7 @@ /* TODO: copy-pasted from above. FIXME */ if ((size_t)matches_len + matches_spare >= matches_size) { matches_size = matches ? matches_size * 2 : 100; - log_debug("Too many matches in %s. Reallocating matches to %zu.", dir_full_path, matches_size); - matches = ag_realloc(matches, matches_size * sizeof(match)); + matches = ag_realloc(matches, matches_size * sizeof(match_t)); } matches[matches_len].start = offset_vector[0]; @@ -117,7 +115,7 @@ } if (opts.invert_match) { - matches_len = invert_matches(matches, matches_len, buf_len); + matches_len = invert_matches(buf, buf_len, matches, matches_len); } if (opts.stats) { @@ -142,7 +140,7 @@ * GitHub issue 206 for the consequences if this behaviour is not * checked. */ if (!opts.invert_match || matches_len < 2) { - print_path(dir_full_path, '\n'); + print_path(dir_full_path, opts.null_follows_filename ? 0 : '\n'); } } else if (binary) { print_binary_file_matches(dir_full_path); @@ -150,6 +148,9 @@ print_file_matches(dir_full_path, buf, buf_len, matches, matches_len); } pthread_mutex_unlock(&print_mtx); + opts.match_found = 1; + } else if (opts.search_stream && opts.passthrough) { + fprintf(out_fd, "%s", buf); } else { log_debug("No match in %s", dir_full_path); } @@ -210,71 +211,79 @@ pipe = fdopen(fd, "r"); search_stream(pipe, file_full_path); fclose(pipe); - } else { - f_len = statbuf.st_size; + goto cleanup; + } - if (f_len == 0) { - log_debug("Skipping %s: file is empty.", file_full_path); - goto cleanup; - } + f_len = statbuf.st_size; - if (!opts.literal && f_len > INT_MAX) { - log_err("Skipping %s: pcre_exec() can't handle files larger than %i bytes.", file_full_path, INT_MAX); - goto cleanup; - } + if (f_len == 0) { + log_debug("Skipping %s: file is empty.", file_full_path); + goto cleanup; + } + + if (!opts.literal && f_len > INT_MAX) { + log_err("Skipping %s: pcre_exec() can't handle files larger than %i bytes.", file_full_path, INT_MAX); + goto cleanup; + } #ifdef _WIN32 - { - HANDLE hmmap = CreateFileMapping( - (HANDLE)_get_osfhandle(fd), 0, PAGE_READONLY, 0, f_len, NULL); - buf = (char *)MapViewOfFile(hmmap, FILE_SHARE_READ, 0, 0, f_len); - if (hmmap != NULL) - CloseHandle(hmmap); - } - if (buf == NULL) { - FormatMessageA( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, GetLastError(), 0, (void *)&buf, 0, NULL); - log_err("File %s failed to load: %s.", file_full_path, buf); - LocalFree((void *)buf); - goto cleanup; - } + { + HANDLE hmmap = CreateFileMapping( + (HANDLE)_get_osfhandle(fd), 0, PAGE_READONLY, 0, f_len, NULL); + buf = (char *)MapViewOfFile(hmmap, FILE_SHARE_READ, 0, 0, f_len); + if (hmmap != NULL) + CloseHandle(hmmap); + } + if (buf == NULL) { + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, GetLastError(), 0, (void *)&buf, 0, NULL); + log_err("File %s failed to load: %s.", file_full_path, buf); + LocalFree((void *)buf); + goto cleanup; + } #else - buf = mmap(0, f_len, PROT_READ, MAP_SHARED, fd, 0); - if (buf == MAP_FAILED) { - log_err("File %s failed to load: %s.", file_full_path, strerror(errno)); - goto cleanup; - } + buf = mmap(0, f_len, PROT_READ, MAP_SHARED, fd, 0); + if (buf == MAP_FAILED) { + log_err("File %s failed to load: %s.", file_full_path, strerror(errno)); + goto cleanup; + } +#if HAVE_MADVISE + madvise(buf, f_len, MADV_SEQUENTIAL); +#elif HAVE_POSIX_FADVISE + posix_fadvise(fd, 0, f_len, POSIX_MADV_SEQUENTIAL); +#endif #endif - if (opts.search_zip_files) { - ag_compression_type zip_type = is_zipped(buf, f_len); - if (zip_type != AG_NO_COMPRESSION) { - int _buf_len = (int)f_len; - char *_buf = decompress(zip_type, buf, f_len, file_full_path, &_buf_len); - if (_buf == NULL || _buf_len == 0) { - log_err("Cannot decompress zipped file %s", file_full_path); - goto cleanup; - } - search_buf(_buf, _buf_len, file_full_path); - free(_buf); + if (opts.search_zip_files) { + ag_compression_type zip_type = is_zipped(buf, f_len); + if (zip_type != AG_NO_COMPRESSION) { + int _buf_len = (int)f_len; + char *_buf = decompress(zip_type, buf, f_len, file_full_path, &_buf_len); + if (_buf == NULL || _buf_len == 0) { + log_err("Cannot decompress zipped file %s", file_full_path); goto cleanup; } + search_buf(_buf, _buf_len, file_full_path); + free(_buf); + goto cleanup; } - - search_buf(buf, (int)f_len, file_full_path); } + search_buf(buf, f_len, file_full_path); + cleanup: - if (fd != -1) { + if (buf != NULL) { #ifdef _WIN32 UnmapViewOfFile(buf); #else munmap(buf, f_len); #endif + } + if (fd != -1) { close(fd); } } @@ -411,9 +420,11 @@ } else if (results == -1) { if (errno == ENOTDIR) { /* Not a directory. Probably a file. */ - /* If we're only searching one file, don't print the filename header at the top. */ if (depth == 0 && opts.paths_len == 1) { - opts.print_heading = -1; + /* If we're only searching one file, don't print the filename header at the top. */ + if (opts.print_path == PATH_PRINT_DEFAULT || opts.print_path == PATH_PRINT_DEFAULT_EACH_LINE) { + opts.print_path = PATH_PRINT_NOTHING; + } } search_file(path); } else { @@ -469,11 +480,25 @@ } else if (opts.recurse_dirs) { if (depth < opts.max_search_depth) { log_debug("Searching dir %s", dir_full_path); - ignores *child_ig = init_ignore(ig); + ignores *child_ig; + // #if defined(__MINGW32__) || defined(__CYGWIN__) + child_ig = init_ignore(ig, dir->d_name, strlen(dir->d_name)); + // #else + // child_ig = init_ignore(ig, dir->d_name, dir->d_namlen); + // #endif search_dir(child_ig, base_path, dir_full_path, depth + 1); cleanup_ignore(child_ig); } else { - log_err("Skipping %s. Use the --depth option to search deeper.", dir_full_path); + if (opts.max_search_depth == DEFAULT_MAX_SEARCH_DEPTH) { + /* + * If the user didn't intentionally specify a particular depth, + * this is a warning... + */ + log_warn("Skipping %s. Use the --depth option to search deeper.", dir_full_path); + } else { + /* ... if they did, let's settle for debug. */ + log_debug("Skipping %s. Use the --depth option to search deeper.", dir_full_path); + } } } diff -Nru silversearcher-ag-0.22.0/src/search.h silversearcher-ag-0.26.0/src/search.h --- silversearcher-ag-0.22.0/src/search.h 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/src/search.h 2014-10-24 20:50:41.000000000 +0000 @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -20,6 +19,10 @@ #include "config.h" +#ifdef HAVE_PTHREAD_H +#include +#endif + #include "ignore.h" #include "log.h" #include "options.h" @@ -27,7 +30,8 @@ #include "util.h" #include "uthash.h" -size_t skip_lookup[256]; +size_t alpha_skip_lookup[256]; +size_t *find_skip_lookup; struct work_queue_t { char *path; diff -Nru silversearcher-ag-0.22.0/src/util.c silversearcher-ag-0.26.0/src/util.c --- silversearcher-ag-0.22.0/src/util.c 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/src/util.c 2014-10-24 20:50:41.000000000 +0000 @@ -41,11 +41,18 @@ } char *ag_strndup(const char *s, size_t size) { - char *str = strndup(s, size); + char *str = NULL; +#ifdef HAVE_STRNDUP + str = strndup(s, size); CHECK_AND_RETURN(str) +#else + str = (char *)ag_malloc(size + 1); + strlcpy(str, s, size + 1); + return str; +#endif } -void generate_skip_lookup(const char *find, size_t f_len, size_t skip_lookup[], int case_sensitive) { +void generate_alpha_skip(const char *find, size_t f_len, size_t skip_lookup[], const int case_sensitive) { size_t i; for (i = 0; i < 256; i++) { @@ -55,52 +62,111 @@ f_len--; for (i = 0; i < f_len; i++) { - skip_lookup[(unsigned char)find[i]] = f_len - i; - if (!case_sensitive) { + if (case_sensitive) { + skip_lookup[(unsigned char)find[i]] = f_len - i; + } else { + skip_lookup[(unsigned char)tolower(find[i])] = f_len - i; skip_lookup[(unsigned char)toupper(find[i])] = f_len - i; } } } -/* Boyer-Moore-Horspool strstr */ -const char *boyer_moore_strnstr(const char *s, const char *find, const size_t s_len, const size_t f_len, const size_t skip_lookup[]) { +int is_prefix(const char *s, const size_t s_len, const size_t pos, const int case_sensitive) { size_t i; - size_t pos = 0; - /* It's impossible to match a larger string */ - if (f_len > s_len) { - return NULL; + for (i = 0; pos + i < s_len; i++) { + if (case_sensitive) { + if (s[i] != s[i + pos]) { + return 0; + } + } else { + if (tolower(s[i]) != tolower(s[i + pos])) { + return 0; + } + } } - while (pos <= (s_len - f_len)) { - for (i = f_len - 1; s[pos + i] == find[i]; i--) { - if (i == 0) { - return &(s[pos]); + return 1; +} + +size_t suffix_len(const char *s, const size_t s_len, const size_t pos, const int case_sensitive) { + size_t i; + + for (i = 0; i < pos; i++) { + if (case_sensitive) { + if (s[pos - i] != s[s_len - i - 1]) { + break; + } + } else { + if (tolower(s[pos - i]) != tolower(s[s_len - i - 1])) { + break; } } - pos += skip_lookup[(unsigned char)s[pos + f_len - 1]]; } - return NULL; + return i; } -/* Copy-pasted from above. Yes I know this is bad. One day I might even fix it. */ -const char *boyer_moore_strncasestr(const char *s, const char *find, const size_t s_len, const size_t f_len, const size_t skip_lookup[]) { +void generate_find_skip(const char *find, const size_t f_len, size_t **skip_lookup, const int case_sensitive) { size_t i; - size_t pos = 0; + size_t s_len; + size_t *sl = ag_malloc(f_len * sizeof(size_t)); + *skip_lookup = sl; + size_t last_prefix = f_len; + + for (i = last_prefix; i > 0; i--) { + if (is_prefix(find, f_len, i, case_sensitive)) { + last_prefix = i; + } + sl[i - 1] = last_prefix + (f_len - i); + } - /* It's impossible to match a larger string */ - if (f_len > s_len) { - return NULL; + for (i = 0; i < f_len; i++) { + s_len = suffix_len(find, f_len, i, case_sensitive); + if (find[i - s_len] != find[f_len - 1 - s_len]) { + sl[f_len - 1 - s_len] = f_len - 1 - i + s_len; + } } +} - while (pos <= (s_len - f_len)) { - for (i = f_len - 1; tolower(s[pos + i]) == find[i]; i--) { - if (i == 0) { - return &(s[pos]); - } +size_t ag_max(size_t a, size_t b) { + if (b > a) { + return b; + } + return a; +} + +/* Boyer-Moore strstr */ +const char *boyer_moore_strnstr(const char *s, const char *find, const size_t s_len, const size_t f_len, + const size_t alpha_skip_lookup[], const size_t *find_skip_lookup) { + ssize_t i; + size_t pos = f_len - 1; + + while (pos < s_len) { + for (i = f_len - 1; i >= 0 && s[pos] == find[i]; pos--, i--) { + } + if (i < 0) { + return s + pos + 1; + } + pos += ag_max(alpha_skip_lookup[(unsigned char)s[pos]], find_skip_lookup[i]); + } + + return NULL; +} + +/* Copy-pasted from above. Yes I know this is bad. One day I might even fix it. */ +const char *boyer_moore_strncasestr(const char *s, const char *find, const size_t s_len, const size_t f_len, + const size_t alpha_skip_lookup[], const size_t *find_skip_lookup) { + ssize_t i; + size_t pos = f_len - 1; + + while (pos < s_len) { + for (i = f_len - 1; i >= 0 && tolower(s[pos]) == find[i]; pos--, i--) { } - pos += skip_lookup[(unsigned char)s[pos + f_len - 1]]; + if (i < 0) { + return s + pos + 1; + } + pos += ag_max(alpha_skip_lookup[(unsigned char)s[pos]], find_skip_lookup[i]); } return NULL; @@ -116,41 +182,69 @@ return ag_strncmp_fp; } -size_t invert_matches(match matches[], size_t matches_len, const size_t buf_len) { +size_t invert_matches(const char *buf, const size_t buf_len, match_t matches[], size_t matches_len) { size_t i; + size_t match_read_index = 0; + size_t inverted_match_count = 0; + size_t inverted_match_start = 0; + size_t last_line_end = 0; + int in_inverted_match = TRUE; + match_t next_match; + + log_debug("Inverting %u matches.", matches_len); + + if (matches_len > 0) { + next_match = matches[0]; + } else { + next_match.start = buf_len + 1; + } + /* No matches, so the whole buffer is now a match. */ if (matches_len == 0) { matches[0].start = 0; - matches[0].end = buf_len; + matches[0].end = buf_len - 1; return 1; } - if (matches_len == 1 && matches[0].start == 0 && matches[0].end == buf_len) { - /* entire buffer is a match */ - return 0; - } + for (i = 0; i < buf_len; i++) { + if (i == next_match.start) { + i = next_match.end - 1; - if (matches[0].start == 0) { - for (i = 0; i < matches_len; i++) { - matches[i].start = matches[i].end; - matches[i].end = matches[i + 1].start; - } - matches_len--; - } else { - for (i = matches_len; i > 0; i--) { - matches[i].end = matches[i].start; - matches[i].start = matches[i - 1].end; + match_read_index++; + + if (match_read_index < matches_len) { + next_match = matches[match_read_index]; + } + + if (in_inverted_match && last_line_end > inverted_match_start) { + matches[inverted_match_count].start = inverted_match_start; + matches[inverted_match_count].end = last_line_end - 1; + + inverted_match_count++; + } + + in_inverted_match = FALSE; + } else if (i == buf_len - 1 && in_inverted_match) { + matches[inverted_match_count].start = inverted_match_start; + matches[inverted_match_count].end = i; + + inverted_match_count++; + } else if (buf[i] == '\n') { + last_line_end = i + 1; + + if (!in_inverted_match) { + inverted_match_start = last_line_end; + } + + in_inverted_match = TRUE; } - matches[0].end = matches[0].start; - matches[0].start = 0; } - matches[matches_len].end = buf_len; - if (matches[matches_len].start != matches[matches_len].end) { - matches_len++; + for (i = 0; i < matches_len; i++) { + log_debug("Inverted match %i start %i end %i.", i, matches[i].start, matches[i].end); } - return matches_len; + return inverted_match_count; } void compile_study(pcre **re, pcre_extra **re_extra, char *q, const int pcre_opts, const int study_opts) { @@ -445,10 +539,13 @@ #endif #ifndef HAVE_REALPATH +/* + * realpath() for Windows. Turns slashes into backslashes and calls _fullpath + */ char *realpath(const char *path, char *resolved_path) { char *p; char tmp[MAX_PATH + 1]; - strncpy(tmp, path, sizeof(tmp) - 1); + strlcpy(tmp, path, sizeof(tmp)); p = tmp; while (*p) { if (*p == '/') { @@ -456,23 +553,36 @@ } p++; } - return _fullpath(resolved_path, tmp, MAX_PATH); + return _fullpath(resolved_path, tmp, _MAX_PATH); } #endif -#ifndef HAVE_STRNDUP -/* Apache-licensed implementation of strndup for OS - * taken from http://source-android.frandroid.com/dalvik/tools/dmtracedump/CreateTestTrace.c - * modified to check for malloc() failure - */ -char *strndup(const char *src, size_t len) { - char *dest = (char *)malloc(len + 1); - if (!dest) { - return NULL; - } - strncpy(dest, src, len); - dest[len] = 0; - return dest; +#ifndef HAVE_STRLCPY +size_t strlcpy(char *dst, const char *src, size_t size) { + char *d = dst; + const char *s = src; + size_t n = size; + + /* Copy as many bytes as will fit */ + if (n != 0) { + while (--n != 0) { + if ((*d++ = *s++) == '\0') { + break; + } + } + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (size != 0) { + *d = '\0'; /* NUL-terminate dst */ + } + + while (*s++) { + } + } + + return (s - src - 1); /* count does not include NUL */ } #endif diff -Nru silversearcher-ag-0.22.0/src/util.h silversearcher-ag-0.26.0/src/util.h --- silversearcher-ag-0.22.0/src/util.h 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/src/util.h 2014-10-24 20:50:41.000000000 +0000 @@ -31,7 +31,7 @@ typedef struct { size_t start; /* Byte at which the match starts */ size_t end; /* and where it ends */ -} match; +} match_t; typedef struct { long total_bytes; @@ -50,16 +50,24 @@ ag_stats stats; -typedef const char *(*strncmp_fp)(const char *, const char *, const size_t, const size_t, const size_t[]); +typedef const char *(*strncmp_fp)(const char *, const char *, const size_t, const size_t, const size_t[], const size_t *); -void generate_skip_lookup(const char *find, size_t f_len, size_t skip_lookup[], int case_sensitive); - -const char *boyer_moore_strnstr(const char *s, const char *find, const size_t s_len, const size_t f_len, const size_t skip_lookup[]); -const char *boyer_moore_strncasestr(const char *s, const char *find, const size_t s_len, const size_t f_len, const size_t skip_lookup[]); +void generate_alpha_skip(const char *find, size_t f_len, size_t skip_lookup[], const int case_sensitive); +int is_prefix(const char *s, const size_t s_len, const size_t pos, const int case_sensitive); +size_t suffix_len(const char *s, const size_t s_len, const size_t pos, const int case_sensitive); +void generate_find_skip(const char *find, const size_t f_len, size_t **skip_lookup, const int case_sensitive); + +/* max is already defined on spec-violating compilers such as MinGW */ +size_t ag_max(size_t a, size_t b); + +const char *boyer_moore_strnstr(const char *s, const char *find, const size_t s_len, const size_t f_len, + const size_t alpha_skip_lookup[], const size_t *find_skip_lookup); +const char *boyer_moore_strncasestr(const char *s, const char *find, const size_t s_len, const size_t f_len, + const size_t alpha_skip_lookup[], const size_t *find_skip_lookup); strncmp_fp get_strstr(enum case_behavior opts); -size_t invert_matches(match matches[], size_t matches_len, const size_t buf_len); +size_t invert_matches(const char *buf, const size_t buf_len, match_t matches[], size_t matches_len); void compile_study(pcre **re, pcre_extra **re_extra, char *q, const int pcre_opts, const int study_opts); void *decompress(const ag_compression_type zip_type, const void *buf, const int buf_len, const char *dir_full_path, int *new_buf_len); @@ -92,8 +100,8 @@ #ifndef HAVE_REALPATH char *realpath(const char *path, char *resolved_path); #endif -#ifndef HAVE_STRNDUP -char *strndup(const char *s, size_t n); +#ifndef HAVE_STRLCPY +size_t strlcpy(char *dest, const char *src, size_t size); #endif #ifndef HAVE_VASPRINTF int vasprintf(char **ret, const char *fmt, va_list args); diff -Nru silversearcher-ag-0.22.0/src/win32/config.h silversearcher-ag-0.26.0/src/win32/config.h --- silversearcher-ag-0.22.0/src/win32/config.h 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/src/win32/config.h 2014-10-24 20:50:41.000000000 +0000 @@ -1 +1,2 @@ #define HAVE_LZMA_H +#define HAVE_PTHREAD_H diff -Nru silversearcher-ag-0.22.0/tests/bad_path.t silversearcher-ag-0.26.0/tests/bad_path.t --- silversearcher-ag-0.22.0/tests/bad_path.t 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/tests/bad_path.t 2014-10-24 20:50:41.000000000 +0000 @@ -1,9 +1,10 @@ Setup: - $ source $TESTDIR/setup.sh + $ . $TESTDIR/setup.sh Complain about nonexistent path: $ ag foo doesnt_exist ERR: Error stat()ing: doesnt_exist ERR: Error opening directory doesnt_exist: No such file or directory + [1] diff -Nru silversearcher-ag-0.22.0/tests/big/big_file.t silversearcher-ag-0.26.0/tests/big/big_file.t --- silversearcher-ag-0.22.0/tests/big/big_file.t 1970-01-01 00:00:00.000000000 +0000 +++ silversearcher-ag-0.26.0/tests/big/big_file.t 2014-10-24 20:50:41.000000000 +0000 @@ -0,0 +1,21 @@ +Setup and create really big file: + + $ . $TESTDIR/../setup.sh + $ python3 $TESTDIR/create_big_file.py $TESTDIR/big_file.txt + +Search a big file: + + $ $TESTDIR/../../ag --nocolor --workers=1 --parallel hello $TESTDIR/big_file.txt + 33554432:hello1073741824 + 67108864:hello2147483648 + 100663296:hello3221225472 + 134217728:hello4294967296 + 167772160:hello5368709120 + 201326592:hello6442450944 + 234881024:hello7516192768 + 268435456:hello + +Fail to regex search a big file: + $ $TESTDIR/../../ag --nocolor --workers=1 --parallel 'hello.*' $TESTDIR/big_file.txt + ERR: Skipping */big_file.txt: pcre_exec() can't handle files larger than 2147483647 bytes. (glob) + [1] diff -Nru silversearcher-ag-0.22.0/tests/big/create_big_file.py silversearcher-ag-0.26.0/tests/big/create_big_file.py --- silversearcher-ag-0.22.0/tests/big/create_big_file.py 1970-01-01 00:00:00.000000000 +0000 +++ silversearcher-ag-0.26.0/tests/big/create_big_file.py 2014-10-24 20:50:41.000000000 +0000 @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +# Create an 8GB file of mostly "abcdefghijklmnopqrstuvwxyz01234", +# with a few instances of "hello" + +import sys + +if len(sys.argv) != 2: + print("Usage: %s big_file.txt" % sys.argv[0]) + sys.exit(1) + +big_file = sys.argv[1] + + +def create_big_file(): + with open(big_file, "w") as fd: + for i in range(1, 2**28): + byte = i * 32 + if byte % 2**30 == 0: + fd.write("hello%s\n" % byte) + else: + fd.write("abcdefghijklmnopqrstuvwxyz01234\n") + fd.write("hello\n") + + +try: + fd = open(big_file, "r") +except Exception as e: + create_big_file() diff -Nru silversearcher-ag-0.22.0/tests/case_sensitivity.t silversearcher-ag-0.26.0/tests/case_sensitivity.t --- silversearcher-ag-0.22.0/tests/case_sensitivity.t 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/tests/case_sensitivity.t 2014-10-24 20:50:41.000000000 +0000 @@ -1,19 +1,34 @@ Setup: - $ source $TESTDIR/setup.sh + $ . $TESTDIR/setup.sh $ echo Foo >> ./sample $ echo bar >> ./sample -Case sensitive by default: +Smart case by default: $ ag foo sample + 1:Foo $ ag FOO sample + [1] $ ag 'f.o' sample + 1:Foo $ ag Foo sample 1:Foo $ ag 'F.o' sample 1:Foo +Case sensitive mode: + + $ ag -s foo sample + [1] + $ ag -s FOO sample + [1] + $ ag -s 'f.o' sample + [1] + $ ag -s Foo sample + 1:Foo + $ ag -s 'F.o' sample + 1:Foo Case insensitive mode: $ ag foo -i sample diff -Nru silversearcher-ag-0.22.0/tests/exitcodes.t silversearcher-ag-0.26.0/tests/exitcodes.t --- silversearcher-ag-0.22.0/tests/exitcodes.t 1970-01-01 00:00:00.000000000 +0000 +++ silversearcher-ag-0.26.0/tests/exitcodes.t 2014-10-24 20:50:41.000000000 +0000 @@ -0,0 +1,22 @@ +Setup: + + $ . $TESTDIR/setup.sh + $ echo foo > ./exitcodes_test.txt + $ echo bar >> ./exitcodes_test.txt + +Normal matching: + + $ ag foo exitcodes_test.txt + 1:foo + $ ag zoo exitcodes_test.txt + [1] + +Inverted matching: + + $ ag -v foo exitcodes_test.txt + 2:bar + $ ag -v zoo exitcodes_test.txt + 1:foo + 2:bar + $ ag -v "foo|bar" exitcodes_test.txt + [1] diff -Nru silversearcher-ag-0.22.0/tests/hidden_option.t silversearcher-ag-0.26.0/tests/hidden_option.t --- silversearcher-ag-0.22.0/tests/hidden_option.t 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/tests/hidden_option.t 2014-10-24 20:50:41.000000000 +0000 @@ -1,6 +1,6 @@ Setup: - $ source $TESTDIR/setup.sh + $ . $TESTDIR/setup.sh $ mkdir hidden_bug $ cd hidden_bug $ echo "test" > a.txt @@ -8,8 +8,31 @@ $ if [ ! -d .git/info ] ; then mkdir .git/info ; fi $ echo "a.txt" > .git/info/exclude -Do not ignore a.txt + $ ag --ignore-dir .git test + [1] $ ag --hidden --ignore-dir .git test + [1] + + $ ag -U --ignore-dir .git test + a.txt:1:test + + $ ag --hidden -U --ignore-dir .git test a.txt:1:test + $ mkdir -p ./.hidden + $ echo 'whatever' > ./.hidden/a.txt + + $ ag whatever + [1] + + $ ag --hidden whatever + [1] + + $ echo "" > .git/info/exclude + + $ ag whatever + [1] + + $ ag --hidden whatever + .hidden/a.txt:1:whatever diff -Nru silversearcher-ag-0.22.0/tests/ignore_absolute_search_path_with_glob.t silversearcher-ag-0.26.0/tests/ignore_absolute_search_path_with_glob.t --- silversearcher-ag-0.22.0/tests/ignore_absolute_search_path_with_glob.t 1970-01-01 00:00:00.000000000 +0000 +++ silversearcher-ag-0.26.0/tests/ignore_absolute_search_path_with_glob.t 2014-10-24 20:50:41.000000000 +0000 @@ -0,0 +1,16 @@ +Setup: + + $ . $TESTDIR/setup.sh + $ mkdir -p parent/multi-part + $ echo 'match1' > parent/multi-part/file1.txt + $ echo 'parent/multi-*' > .gitignore + +# Ignore directory specified by glob: + +# $ ag match . +# [1] + +# Ignore directory specified by glob with absolute search path (#448): + +# $ ag match $(pwd) +# [1] diff -Nru silversearcher-ag-0.22.0/tests/ignore_abs_path.t silversearcher-ag-0.26.0/tests/ignore_abs_path.t --- silversearcher-ag-0.22.0/tests/ignore_abs_path.t 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/tests/ignore_abs_path.t 2014-10-24 20:50:41.000000000 +0000 @@ -1,6 +1,6 @@ Setup: - $ source $TESTDIR/setup.sh + $ . $TESTDIR/setup.sh $ mkdir -p ./a/b/c $ echo 'whatever1' > ./a/b/c/blah.yml $ echo 'whatever2' > ./a/b/foo.yml @@ -13,6 +13,11 @@ Dont ignore anything (unrestricted search): - $ ag -u whatever . + $ ag -u whatever . | sort a/b/c/blah.yml:1:whatever1 a/b/foo.yml:1:whatever2 + +Ignore foo.yml given an absolute search path [#448]: + + $ ag whatever $(pwd) + /.*/a/b/c/blah.yml:1:whatever1 (re) diff -Nru silversearcher-ag-0.22.0/tests/ignore_backups.t silversearcher-ag-0.26.0/tests/ignore_backups.t --- silversearcher-ag-0.22.0/tests/ignore_backups.t 1970-01-01 00:00:00.000000000 +0000 +++ silversearcher-ag-0.26.0/tests/ignore_backups.t 2014-10-24 20:50:41.000000000 +0000 @@ -0,0 +1,49 @@ +Setup: + + $ . $TESTDIR/setup.sh + $ mkdir -p ./a/b/c + $ echo 'whatever1' > ./a/b/c/foo.yml + $ echo 'whatever2' > ./a/b/c/foo.yml~ + $ echo 'whatever3' > ./a/b/c/.foo.yml.swp + $ echo 'whatever4' > ./a/b/c/.foo.yml.swo + $ echo 'whatever5' > ./a/b/foo.yml + $ echo 'whatever6' > ./a/b/foo.yml~ + $ echo 'whatever7' > ./a/b/.foo.yml.swp + $ echo 'whatever8' > ./a/b/.foo.yml.swo + $ echo 'whatever9' > ./a/foo.yml + $ echo 'whatever10' > ./a/foo.yml~ + $ echo 'whatever11' > ./a/.foo.yml.swp + $ echo 'whatever12' > ./a/.foo.yml.swo + $ echo 'whatever13' > ./foo.yml + $ echo 'whatever14' > ./foo.yml~ + $ echo 'whatever15' > ./.foo.yml.swp + $ echo 'whatever16' > ./.foo.yml.swo + $ echo '*~\n*.sw[po]' > ./.gitignore + +Ignore all files except foo.yml + + $ ag whatever . | sort + a/b/c/foo.yml:1:whatever1 + a/b/foo.yml:1:whatever5 + a/foo.yml:1:whatever9 + foo.yml:1:whatever13 + +Dont ignore anything (unrestricted search): + + $ ag -u whatever . | sort + .foo.yml.swo:1:whatever16 + .foo.yml.swp:1:whatever15 + a/.foo.yml.swo:1:whatever12 + a/.foo.yml.swp:1:whatever11 + a/b/.foo.yml.swo:1:whatever8 + a/b/.foo.yml.swp:1:whatever7 + a/b/c/.foo.yml.swo:1:whatever4 + a/b/c/.foo.yml.swp:1:whatever3 + a/b/c/foo.yml:1:whatever1 + a/b/c/foo.yml~:1:whatever2 + a/b/foo.yml:1:whatever5 + a/b/foo.yml~:1:whatever6 + a/foo.yml:1:whatever9 + a/foo.yml~:1:whatever10 + foo.yml:1:whatever13 + foo.yml~:1:whatever14 diff -Nru silversearcher-ag-0.22.0/tests/ignore_examine_parent_ignorefiles.t silversearcher-ag-0.26.0/tests/ignore_examine_parent_ignorefiles.t --- silversearcher-ag-0.22.0/tests/ignore_examine_parent_ignorefiles.t 1970-01-01 00:00:00.000000000 +0000 +++ silversearcher-ag-0.26.0/tests/ignore_examine_parent_ignorefiles.t 2014-10-24 20:50:41.000000000 +0000 @@ -0,0 +1,22 @@ +Setup: + + $ . $TESTDIR/setup.sh + $ mkdir -p subdir + $ echo 'match1' > subdir/file1.txt + $ echo 'file1.txt' > .gitignore + +Ignore directory specified by name: + + $ ag match + [1] + +# Ignore directory specified by name in parent directory when using path (#144): + +# $ ag match subdir +# [1] + +# Ignore directory specified by name in parent directory when using current directory (#144): + +# $ cd subdir +# $ ag match +# [1] diff -Nru silversearcher-ag-0.22.0/tests/ignore_pattern_in_subdirectory.t silversearcher-ag-0.26.0/tests/ignore_pattern_in_subdirectory.t --- silversearcher-ag-0.22.0/tests/ignore_pattern_in_subdirectory.t 1970-01-01 00:00:00.000000000 +0000 +++ silversearcher-ag-0.26.0/tests/ignore_pattern_in_subdirectory.t 2014-10-24 20:50:41.000000000 +0000 @@ -0,0 +1,17 @@ +Setup: + + $ . $TESTDIR/setup.sh + $ mkdir subdir + $ echo 'first' > file1.txt + $ echo 'second' > subdir/file2.txt + $ echo '*.txt' > .gitignore + +Ignore file based on extension match: + + $ ag first + [1] + +Ignore file in subdirectory based on extension match (#442): + + $ ag second + [1] diff -Nru silversearcher-ag-0.22.0/tests/ignore_subdir.t silversearcher-ag-0.26.0/tests/ignore_subdir.t --- silversearcher-ag-0.22.0/tests/ignore_subdir.t 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/tests/ignore_subdir.t 2014-10-24 20:50:41.000000000 +0000 @@ -1,10 +1,12 @@ Setup: - $ source $TESTDIR/setup.sh + $ . $TESTDIR/setup.sh $ mkdir -p ./a/b/c $ echo 'whatever1' > ./a/b/c/blah.yml $ echo 'whatever2' > ./a/b/foo.yml - $ echo 'a/b/*.yml' > ./.gitignore + $ echo 'a/b/foo.yml' > ./.gitignore +# TODO: have this work instead of the above +# $ echo 'a/b/*.yml' > ./.gitignore Ignore foo.yml but not blah.yml: @@ -13,6 +15,6 @@ Dont ignore anything (unrestricted search): - $ ag -u whatever . + $ ag -u whatever . | sort a/b/c/blah.yml:1:whatever1 a/b/foo.yml:1:whatever2 diff -Nru silversearcher-ag-0.22.0/tests/invert_match.t silversearcher-ag-0.26.0/tests/invert_match.t --- silversearcher-ag-0.22.0/tests/invert_match.t 1970-01-01 00:00:00.000000000 +0000 +++ silversearcher-ag-0.26.0/tests/invert_match.t 2014-10-24 20:50:41.000000000 +0000 @@ -0,0 +1,16 @@ +Setup: + + $ . $TESTDIR/setup.sh + $ echo 'valid: 1' > ./blah.txt + $ echo 'some_string' >> ./blah.txt + $ echo 'valid: 654' >> ./blah.txt + $ echo 'some_other_string' >> ./blah.txt + $ echo 'valid: 0' >> ./blah.txt + $ echo 'valid: 23' >> ./blah.txt + $ echo 'valid: 0' >> ./blah.txt + +Search for lines not matching "valid: 0" in blah.txt: + + $ ag -v 'valid: ' + blah.txt:2:some_string + blah.txt:4:some_other_string diff -Nru silversearcher-ag-0.22.0/tests/list_file_types.t silversearcher-ag-0.26.0/tests/list_file_types.t --- silversearcher-ag-0.22.0/tests/list_file_types.t 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/tests/list_file_types.t 2014-10-24 20:50:41.000000000 +0000 @@ -1,6 +1,6 @@ Setup: - $ source $TESTDIR/setup.sh + $ . $TESTDIR/setup.sh Language types are output: @@ -25,13 +25,13 @@ .cfc .cfm .cfml --clojure - .clj + .clj .cljs .cljx --coffee .coffee --cpp - .cpp .cc .cxx .m .hpp .hh .h .hxx + .cpp .cc .C .cxx .m .hpp .hh .h .H .hxx --csharp .cs @@ -51,35 +51,47 @@ --fortran .f .f77 .f90 .f95 .f03 .for .ftn .fpp + --gettext + .po .pot .mo + --go .go --groovy .groovy .gtmpl .gpp .grunit + --haml + .haml + --haskell .hs .lhs --hh .h - --haml - .haml - --html .htm .html .shtml .xhtml + --ini + .ini + + --jade + .jade + --java .java .properties --js .js + --json + .json + --jsp .jsp .jspx .jhtm .jhtml - --json - .json + --less + .less --lisp .lisp .lsp @@ -90,15 +102,15 @@ --m4 .m4 - --matlab - .m - --make .Makefiles .mk .mak --mason .mas .mhtml .mpl .mtxt + --matlab + .m + --objc .m .h @@ -138,12 +150,12 @@ --rust .rs - --sass - .sass .scss - --salt .sls + --sass + .sass .scss + --scala .scala @@ -159,6 +171,12 @@ --sql .sql .ctl + --stylus + .styl + + --swift + .swift + --tcl .tcl .itcl .itk @@ -174,3 +192,15 @@ --verilog .v .vh .sv + --vhdl + .vhd .vhdl + + --vim + .vim + + --xml + .xml .dtd .xsl .xslt .ent + + --yaml + .yaml .yml + diff -Nru silversearcher-ag-0.22.0/tests/passthrough.t silversearcher-ag-0.26.0/tests/passthrough.t --- silversearcher-ag-0.22.0/tests/passthrough.t 1970-01-01 00:00:00.000000000 +0000 +++ silversearcher-ag-0.26.0/tests/passthrough.t 2014-10-24 20:50:41.000000000 +0000 @@ -0,0 +1,26 @@ +Setup: + + $ . $TESTDIR/setup.sh + $ unalias ag + $ alias ag="$TESTDIR/../ag --nocolor --workers=1" + $ echo "foo bar" > passthrough_test.txt + $ echo "zoo zar" >> passthrough_test.txt + $ echo "foo test" >> passthrough_test.txt + +No impact on non-stream: + + $ ag --passthrough zoo passthrough_test.txt + zoo zar + +Match stream with --passthrough: + + $ cat passthrough_test.txt | ag --passthrough foo + foo bar + zoo zar + foo test + +Match stream without --passthrough: + + $ cat passthrough_test.txt | ag foo + foo bar + foo test diff -Nru silversearcher-ag-0.22.0/tests/stupid_fnmatch.t silversearcher-ag-0.26.0/tests/stupid_fnmatch.t --- silversearcher-ag-0.22.0/tests/stupid_fnmatch.t 2014-05-12 06:17:33.000000000 +0000 +++ silversearcher-ag-0.26.0/tests/stupid_fnmatch.t 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -Setup: - - $ source $TESTDIR/setup.sh - $ mkdir -p ./a/bomb - $ echo 'whatever' > ./a/bomb/foo.yml - $ echo '*b/foo.yml' > ./.gitignore - -Ignore foo.yml but not blah.yml: - - $ ag whatever . - -Dont ignore anything (unrestricted search): - - $ ag -u whatever . - a/bomb/foo.yml:1:whatever diff -Nru silversearcher-ag-0.22.0/tests/stupid_fnmatch.t.disabled silversearcher-ag-0.26.0/tests/stupid_fnmatch.t.disabled --- silversearcher-ag-0.22.0/tests/stupid_fnmatch.t.disabled 1970-01-01 00:00:00.000000000 +0000 +++ silversearcher-ag-0.26.0/tests/stupid_fnmatch.t.disabled 2014-10-24 20:50:41.000000000 +0000 @@ -0,0 +1,15 @@ +Setup: + + $ . $TESTDIR/setup.sh + $ mkdir -p ./a/bomb + $ echo 'whatever' > ./a/bomb/foo.yml + $ echo '*b/foo.yml' > ./.gitignore + +Ignore foo.yml but not blah.yml: + + $ ag whatever . + +Dont ignore anything (unrestricted search): + + $ ag -u whatever . + a/bomb/foo.yml:1:whatever diff -Nru silversearcher-ag-0.22.0/tests/vimgrep.t silversearcher-ag-0.26.0/tests/vimgrep.t --- silversearcher-ag-0.22.0/tests/vimgrep.t 1970-01-01 00:00:00.000000000 +0000 +++ silversearcher-ag-0.26.0/tests/vimgrep.t 2014-10-24 20:50:41.000000000 +0000 @@ -0,0 +1,16 @@ +Setup: + + $ . $TESTDIR/setup.sh + $ echo 'Hello, "Hello, world" programs output "Hello, world".' > ./test_vimgrep.txt + $ echo '"Hello, world" programs are simple programs.' >> ./test_vimgrep.txt + $ echo 'They illustrate the most basic syntax of a programming language' >> ./test_vimgrep.txt + $ echo 'In javascript: alert("Hello, world!");' >> ./test_vimgrep.txt + +Search for lines matching "hello" in test_vimgrep.txt: + + $ ag --vimgrep hello + test_vimgrep.txt:1:1:Hello, "Hello, world" programs output "Hello, world". + test_vimgrep.txt:1:9:Hello, "Hello, world" programs output "Hello, world". + test_vimgrep.txt:1:40:Hello, "Hello, world" programs output "Hello, world". + test_vimgrep.txt:2:2:"Hello, world" programs are simple programs. + test_vimgrep.txt:4:23:In javascript: alert("Hello, world!"); diff -Nru silversearcher-ag-0.22.0/.travis.yml silversearcher-ag-0.26.0/.travis.yml --- silversearcher-ag-0.22.0/.travis.yml 1970-01-01 00:00:00.000000000 +0000 +++ silversearcher-ag-0.26.0/.travis.yml 2014-10-24 20:50:41.000000000 +0000 @@ -0,0 +1,18 @@ +language: c + +branches: + only: + - master + +notifications: + email: + - geoff@greer.fm + +install: + - sudo apt-get install -y automake pkg-config libpcre3-dev zlib1g-dev liblzma-dev + +script: + - ./build.sh && make test + +before_script: + - sudo pip install cram