#!/bin/sh
# $Id: ocs,v 1.2 2004/07/09 21:34:43 nicolai Exp $
# This utility maintains the database for cscope on a recursive dir set
# Author:   donwo	Tue Jun 25 15:36:39 PDT 1996
# Modified: hops Jan 2000  chg defaults to not update if files exist and force
#
# These comments ARE the manual.  What more do you really need?
# if using unadorned cscope with this use cscope -d so not trash db
#                    cscope -L -0 <ptn> - to display ptn matches on stdout
#
# The lists of files are kept in two forms:
#	TMP	cscope.tmplst
#               The list generated by this program
#		This list will be updated each time this program
#		is executed.
#
#	LST	cscope.lst
#               The fixed list generated by some other process
#		This list will be used, if found, rather than
#		the TMP form generated here.
# 
#	CSD	cscope.csd
#               The fixed list generated by some other process
#		This list will be used, if found, rather than
#		the LST or TMP forms.  CSD differs from LST in
#		that the CSD list is used where the source files
#		change only seldom.  Cscope is requested not to
#		check for changed files.  This can be
#		significantly faster on large source trees.
#
#	INC	cscope.inc
#               This is a list of additional directories
#		in which to search for include files.
#
# Three hierarchies of libraries are supported:
#	Local	In the current directory	./
#		This is most useful for transient projects or
#		where the information is of no use to others on
#		the system.  This type is NOT usable on source
#		directories that are read-only.
#	Home	In users home directory		$HOME/lib/cs/`pwd`
#		This is good for items that seldom change but are
#		of use only the the current user.  This type is
#		usable on source directories that are read-only.
#	System	In a global system directory	$SYSDIR/`pwd`
#		This is for items that are of interest to all accounts.
#		This option is not available unless the system directory
#		is writable by the current user.  This type is usable
#		on source directories that are read-only.
#
# If a shell script named ./cscope.rc is found and is
# executable, the execution of it will be included within this
# script after defaults_set/cmdline_parse and locating the
# database.
#
# Command line options:
#	-x	set shell debugging
#	-f	force
#		  o  Do not ask about regenerating TMP.  Just do it.
#		  o  Allow cscope to regenerate libraries for CSD lists.
#	-q	Tell cscope to build an inverted index for quick
#		symbol searching.  There is a SIGNIFICANT
#		increase in speed with this option however the
#		disk space used is doubled.  Once the quick
#		database is generated, cs will detect the files
#		and continue to use them.
#	-d	Do not regenerate.  Intended for cscope sub-tasks.
#	-u	Update/regenerate.

#
# Here is where we put things

CSCOPE=cscope
SYSDIR=/usr/local/lib/cs
HOMEDIR=${HOME}/lib/cs

# Check that cscope is in PATH
type cscope 1>/dev/null 2>&1

if [ $? -ne 0 ]
then
	echo "ERROR: cscope is not in \$PATH" >&2
	echo "       Please set \$PATH correctly or make sure cscope is installed" >&2
	exit 1
fi

# popup editor 
#XCS_EDITOR=${HOME}/bin/x_cscope_editor
XCS_EDITOR=${HOME}/bin/xme
if [ -n "$DISPLAY" -a -x ${XCS_EDITOR} ]
then
	EDITOR=${XCS_EDITOR}
	export EDITOR
fi
unset XCS_EDITOR

#
# Misc defaults

#FORCE=N
#NOUPDATE=
FORCE=Y         # hops - default to force rather than query
NOUPDATE=-d     # hops - default to no update if files already exist
QUICK=
SPECDEST=       # hops - query for files

#
# Parse the command line

set -- `getopt xfqdu $*`

if [ $? -ne 0 ]
then
    echo "Use: cs [-x] [-f] [-q] [-u]" >&2
    echo " -x debug on " >&2
    echo " -q quick Index - faster search but larger index" >&2
    echo " -f ask about about regeneration" >&2
    echo " -d don't update database (default)" >&2
    echo " -u update database" >&2
    echo " -s specify where files go" >&2
    exit 1
fi

for arg
do
    case $arg in
	-x )	set -x;     shift	;;
	-f )	FORCE=N; NOUPDATE=; shift;;
	-q )	QUICK=-q;    shift	;;
	-d )	NOUPDATE=-d; shift	;;
	-u )	NOUPDATE=;   shift	;;
	-s )	SPECDEST=Y;   shift	;;
    esac
done

#
# Here is the security hole.  Execute whatever is needed for
# this project.  A per-project setup script may be available.

[ -x ./cscope.rc ] && {
    . ./cscope.rc
}

#
# We look hard for appropriate files to scope.  We ignore items
# containing "SCCS" assuming that these are directories of
# source code control data.

create_list()
{
    LIST=$1

    if [ -f ${LIST} ]
    then
	[ -n "${NOUPDATE}" ] && return

	if [ "${FORCE}" != "Y" ]
	then
	    echo "\n${LIST}"
	    echo "Update the library? <(Y)es, (N)o, (Q)uit> [n] \c"
	    read x y
	    case $x in
		[Yy]* )	;;
		[Qq]* )	exit 1	;;
		*)	return	;;
	    esac
	fi
	echo "Updating library:\n  ${LIST} \c"
    else
	echo "Creating library:\n  ${LIST} \c"
    fi

    (
	find . -follow -type f \( -name \*.[sScChHlyG] -o \
				  -name \*.asm -o \
				  -name \*.cc -o \
				  -name \*.cxx -o \
				  -name \*.ccP -o \
				  -name \*.hP -o \
				  -name \*.inc -o \
				  -name \*.ed -o \
				  -name vuifile -o \
				  -name Gensymvals -o \
				  -name \[mM\]ake\* \) \
				  -print
   ) | grep -v SCCS | sort -u > ${LIST}

    echo "\n`cat ${LIST} | wc -l` files listed"
}

#
# Expand the include file list into command line arguments

exp_inc()
{
    theInc=$1

    if [ -s "${theInc}" ]
    then
	for i in `cat ${theInc}`
	do
	    echo "-I $i \c"
	done
    fi
}

#
# This routine does not return to the caller

do_cscope()
{
    LIST=$1
    CSLIB=$2
    INC=$3
    shift;shift;shift
    ARGS="$*"

    INCARGS=`exp_inc ${INC}`

    echo "exec cscope"
    exec $CSCOPE ${ARGS} -p 2 ${INCARGS} -i ${LIST} -f ${CSLIB}
    echo "exec of $CSCOPE failed" >&2
    exit 1
}

#
# If we have existing libraries, we should use them.
std_libs()
{
    DIR=$1
    OUT=${DIR}/cscope.out
    LST=${DIR}/cscope.lst
    CSD=${DIR}/cscope.csd
    TMP=${DIR}/cscope.tmplst
    INC=${DIR}/cscope.inc
    QCK=${DIR}/cscope.out.po

    [ -s ${QCK} ] && QUICK=-q

    [ -f ${CSD} ] && {
	if [ "${FORCE}" = "Y" ]
	then
	    do_cscope ${CSD} ${OUT} ${INC} ${QUICK}
	else
	    do_cscope ${CSD} ${OUT} ${INC} ${QUICK} -d
	fi
    }

    [ -f ${LST} ] && do_cscope ${LST} ${OUT} ${INC} ${QUICK} ${NOUPDATE}

    [ -f ${TMP} ] && {
	create_list ${TMP}
	do_cscope ${TMP} ${OUT} ${INC} ${QUICK} ${NOUPDATE}
    }
}

#
# ######## main() #######

umask 0
PWD=`pwd`

umask 02

#
# Check for existing libraries

std_libs $PWD
std_libs ${HOMEDIR}$PWD
std_libs ${SYSDIR}$PWD

#
# We may need to create one for this area

DIR=$PWD
if [ ! -n "${NOUPDATE}" -o -n "${SPECDEST}" ] ; then
echo "Create new library? <(L)ocal, (H)ome, (S)ystem, (Q)uit> [q] \c"
read x y
case $x in
    [Ll]* )	DIR=$PWD		;;
    [Hh]* )	DIR=${HOMEDIR}$PWD	;;
    [Ss]* )	DIR=${SYSDIR}$PWD	;;
    *)		exit 1			;;
esac
fi
[ -d $DIR ] || {
    mkdir -p $DIR || exit $?
}

OUT=${DIR}/cscope.out
TMP=${DIR}/cscope.tmplst
INC=${DIR}/cscope.inc

create_list ${TMP}
do_cscope ${TMP} ${OUT} ${INC} ${QUICK}

