#!/usr/bin/env bash

# Copyright (C) 2008-2013 Bob Hepple
#
# 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 2 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, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

# http://bhepple.freeshell.org

set -eu

check_and_process_opts() {
    DEFAULT_IFS=$' \t\n'
    IFS="$DEFAULT_IFS"
    PROG=$(basename $0)
    VERSION="1.6"
    SHORT_DESC="Wrapper around find and grep. "
    USAGE="\
Uses find(1) and grep(1) to recursively search files for regular
expressions. Ignores *~, TAGS and cscope* files. Always applies -I
(ignore binary files).

'$PROG -n' is suitable as emacs' grep function."

    FILE_FILTER=""
    GREP="grep"
    GREP_OPTIONS="-I -H"
    EXCLUDE=""
    VERBOSE=""
    ARGUMENTS="pattern"
    EXCLDIRS=

    ARGS="
ARGP_DELETE=quiet
ARGP_VERSION=$VERSION
ARGP_PROG=$PROG
##############################################################   
#OPTIONS:
#name=default            sname arg       type range   description
##############################################################   
C_FILES=''               c     ''        b    ''      only looks at *.[ch] *.cpp *.cxx files
H_FILES=''               H     ''        b    ''      only looks at *.h files
XML_FILES=''             x     ''        b    ''      only looks at *.xml files
JAVA_FILES=''            j     ''        b    ''      only looks at *.java files
M4_FILES=''              m     ''        b    ''      only looks at *.m4 files
MAKE_FILES=''            M     ''        b    ''      only looks at *akefile* *.mk files
PYTHON_FILES=''          p     ''        b    ''      only looks at *.py files
RUBY_FILES=''            r     ''        b    ''      only looks at *.rb files
SPEC_FILES=''            s     ''        b    ''      only looks at *.spec files
SHELL_FILES=''           ''    ''        b    ''      only looks at *.sh files
EXTENDED_REGEXP=''       E     ''        b    ''      use extended regular expression (as grep)
FIXED_STRINGS=''         F     ''        b    ''      use fixed strings (as grep)
IGNORE_CASE=''           i     ''        b    ''      ignore case (as grep)
files-with-matches=''    l     ''        b    ''      filename only (as grep)
files-without-matches='' L     ''        b    ''      filename only: without match (as grep)
line-number=''           n     ''        b    ''      prefix each hit with the line number (as grep)
context=''               C     lines     i    '1:100' print 'context' lines of context.
EXCLUDE=''               ''    directory s:   ''      exclude directory(s)
EXTENSION=''             ''    ext       s    ''      extensions to search ie *.\$ext

##############################################################   
ARGP_ARGS=[--] $ARGUMENTS
ARGP_SHORT=$SHORT_DESC
ARGP_USAGE=$USAGE"

    exec 4>&1
    eval $(echo "$ARGS" | argp.sh "$@" 3>&1 1>&4 || echo exit $? )
    exec 4>&-

    [[ "$C_FILES" ]] && FILE_FILTER='-a \( -name "*.[ch]" -o -name "*.cpp" -o -name "*.cxx" \)'
    [[ "$H_FILES" ]] && FILE_FILTER='-a -name "*.h"'
    [[ "$XML_FILES" ]] &&  FILE_FILTER='-a \( -name "*.[ch]" -o -name "*.cpp" -o -name "*.cxx" \)'
    [[ "$JAVA_FILES" ]] && FILE_FILTER='-a -name "*.java"'
    [[ "$M4_FILES" ]] && FILE_FILTER='-a -name "*.m4"'
    [[ "$MAKE_FILES" ]] && FILE_FILTER='-a \( -name "*akefile*" -o -name "*.mk" \)'
    [[ "$PYTHON_FILES" ]] && FILE_FILTER='-a -name "*.py"'
    [[ "$RUBY_FILES" ]] && FILE_FILTER='-a -name "*.rb"'
    [[ "$SPEC_FILES" ]] && FILE_FILTER='-a -name "*.spec"'
    [[ "$SHELL_FILES" ]] && FILE_FILTER='-a -name "*.sh"'
    [[ "$EXTENDED_REGEXP" ]] && GREP_OPTIONS+=" -E"
    [[ "$FIXED_STRINGS" ]] && GREP_OPTIONS+=" -F"
    [[ "$IGNORE_CASE" ]] && GREP_OPTIONS+=" -i"
    [[ "$FILES_WITH_MATCHES" ]] && GREP_OPTIONS+=" -l"
    [[ "$FILES_WITHOUT_MATCHES" ]] && GREP_OPTIONS+=" -L"
    [[ "$LINE_NUMBER" ]] && GREP_OPTIONS+=" -n"
    [[ "$CONTEXT" ]] && GREP_OPTIONS+=" -C $CONTEXT"
    [[ "$EXCLUDE" ]] && {
        IFS=:
        for D in $EXCLUDE; do
            EXCLDIRS+="-path '*/$D' -prune -o "
        done
    }
    [[ "$EXTENSION" ]] && FILE_FILTER='-a -name "*.'$EXTENSION'"'

    NEW_ARGS=( "$@" )

    if (( $# == 0 ))
    then
        echo "$PROG: no search expression" >&2
        return 1
    fi
    
    return 0
}

find_string() {

    for EXCLDIR in .svn nbproject .libs .deps 'CVS*'; do
        EXCLDIRS+="-path '*/$EXCLDIR' -prune -o "
    done

    EXPR="find . -follow $EXCLDIRS \\( -type f -a ! -name 'cscope*' -a ! -name TAGS -a ! -name '*~' \\) $FILE_FILTER -exec $GREP $GREP_OPTIONS -- \"$@\" {} \\;"
    [ "$VERBOSE" ] && echo "$EXPR"
    eval $EXPR
}

NEW_ARGS=( )
check_and_process_opts "$@" || exit $?
set -- "${NEW_ARGS[@]:-}"

find_string "$@"
