#!/bin/sh
# [Gedit Tool]
# Name=Cscope
# Shortcut=<Control><Alt>c
# Applicability=all
# Output=output-panel
# Input=selection
# Save-files=nothing

## gedit "external tools" plugin which uses the cscope tool to look up symbols
# in a C or C++ (or whatever else cscope supports) software project
#
# @param  symbol (stdin) the symbol to look up

##############################################################################
# Helper functions                                                           #
##############################################################################

## Assert function - exits with a message if the first parameter is empty
# @param  Condition  ($1) this condition must be a non-empty string for the
#                    assertion to succeed
# @param  Message... ($2, ...) the message to printf to standard error if the
#                    assertion fails
cscopeAssert()
{
    if test -z "$1"; then
        shift
        assertText="`printf "$@"`"
        showText="echo 1>&2"
        command -v zenity > /dev/null && showText="zenity --error --text "
        $showText "$assertText"
        exit 1
    fi
}

## Gettext alias
gtxt="`command -v gettext`"
case "$gtxt" in
    "") gtxt="printf %s";;
esac

## Prinf a message to stdout describing the format of the CSCOPEINFO file
infoFileUsage()
{
    usageText=\
"The do_cscope.sh file should be located in the root folder of your project\
and should execute cscope with the parameters you need, passing on any command\
line arguments (normally -L -[0-9]pattern)."
    $gtxt "$usageText"
}

##############################################################################
# Main body                                                                  #
##############################################################################

## Check that cscope is installed
cscopeAssert "`command -v cscope`" "`$gtxt "The cscope command was not found.  Exiting\n"`"

## Look for a cscope shell wrapper ("do_cscope.sh") by walking up the directory
# structure until we find it or reach the root or a directory we can't read.
# Change to the directory contaning the wrapper.
#
# @returns Sets the global variable CSCOPEWRAPPER to the file found or exits on
#          failure.
# @param   GEDIT_CURRENT_DOCUMENT_DIR (variable) where to start looking
CSCOPEWRAPPER=""
CSCOPEDIR="$GEDIT_CURRENT_DOCUMENT_DIR"
while test "$CSCOPEDIR" != "/" -a -x "$CSCOPEDIR" -a -z "$CSCOPEWRAPPER"; do
    if test -r "$CSCOPEDIR/do_cscope.sh"; then
        CSCOPEWRAPPER="$CSCOPEDIR/do_cscope.sh"
    else
        CSCOPEDIR=`dirname "$CSCOPEDIR"`
    fi
done
cscopeAssert "$CSCOPEWRAPPER" "`$gtxt "Failed to find the CSCOPEWRAPPER file\n\n%s\n"`" "`infoFileUsage`"
cd "$CSCOPEDIR"

# Check that our argument is a single word, possibly with spaces before or
# after.  If we have no argument try to prompt the user for one.
#
# @returns symbol (variable) the argument
symbol="`cat`"
case "$symbol" in "")
    title="`$gtxt "Find symbol"`"
    text="`$gtxt "Please enter the name of a symbol to search for"`"
    command -v zenity > /dev/null &&
        symbol=`zenity --entry --title "$title" --text "$text"`
;; esac
case "$symbol" in "")
    cscopeAssert "" "`$gtxt "You must supply a symbol to search for.\n"`"
;; esac
case "`expr "$symbol" : "^ *\([^ ][^ ]*\) *$"`" in "")
    cscopeAssert "" "`$gtxt "You must supply a single word as the symbol to search for.\n"`"
;; esac

## And now print out the symbols found
# 
# @param  CSCOPEWRAPPER (variable) the cscope cross-reference file
# @param  symbol        (variable) the symbol to search for
CURDIR="`pwd`/"
printf "`$gtxt "Found the following uses of the symbol %s:\n"`" "$symbol"
echo
$CSCOPEWRAPPER -L -3 $symbol | sed 's?\([^ ]*\)  *[a-zA-Z0-9_:]*  *\([0-9]*\) *?'$CURDIR'\1:\2:\n  ?'
echo
printf "`$gtxt "Found the following definitions of the symbol %s:\n"`" "$symbol"
echo
$CSCOPEWRAPPER -L -1 $symbol | sed 's?\([^ ]*\)  *[a-zA-Z0-9_:]*  *\([0-9]*\) *?'$CURDIR'\1:\2:\n  ?'
