#! /bin/sh
#
# $Id: jtags,v 1.12 2002/09/16 04:53:11 paulk Exp $
#
# Usage:     jtags [-h | srcdir]
#
# Abstract:  This Bourne shell script produces an Emacs
#            tags file for Java source code. The tags file
#            contains tags for classes, interfaces, constructors,
#            methods, and variables.
#
# Options:   -h  Print usage.
#
#            -srcdir  Path of top-level directory containing 
#                     Java source(*.java) files to be tagged.
#                     If omitted, this script tags files in
#                     the working directory and its subdirectories.
#
# By:        Paul Kinnucan 
#            The MathWorks, Inc.
#	     paulk@mathworks.com
#
# Thanks:    David Lim <david@ndc.com>
#            Michael Mirman <mmirman@mathworks.com>
#            Kent S. Gordon" <kgor@inetspace.com>
#
# Set this to the path of the etags executable if it is
# not in the shell path.
etags_dir=""

# Print help.
if [ "$1" = "-h" ] || [ "$1" = "-help" ] ||
   [ "$1" = "-usage" ]; then
    echo ""
    echo "usage: jtags [-h | srcdir]"
    echo ""
    echo "srcdir   Path of the Java source directory."
    echo ""
    echo "This command tags all public classes, interfaces,"
    echo "methods, and variables in the specified Java source"
    echo "hierarchy. If you do not specify a source directory," 
    echo "jtags searches the current directory and its"
    echo "subdirectories."
    echo ""
    exit 1
fi

# If not the help option, assume first (should be only) parameter
# is the source path. If no parameters, default to the working
# directory.
java_dir=${1-.}

# Ensure that Java source directory exists.
if [ ! -d $java_dir ]; then
    echo "Java source directory $java_dir not found."
    exit 1
fi

capital='A-Z'
letter='a-zA-Z_.'
digit='0-9'
ws='[ \t]'

primitive_type1='\<\(b\(oolean\|yte\)\|char\|double\|float\|int'
primitive_type2='\|long\|short\|void\)\>'
primitive_type="$primitive_type1$primitive_type2"
primitive_type_count=2

primitive_type3='\|long\|short\)\>'
primitive_type_no_void="$primitive_type1$primitive_type3"
primitive_type_no_void_count=2

identifier="\<\([$letter][$letter$digit]*\)\>"
identifier_count=1

class_type="\<\([$capital][a-zA-Z_$digit\.]*\)\>"
class_type_count=1

modifier1='\<\(abstract\|const\|final\|native\|'
modifier2='p\(r\(ivate\|otected\)\|ublic\)\|'
modifier3='s\(tatic\|ynchronized\)\|transient\|volatile\)\>'
modifier="$modifier1$modifier2$modifier3"
modifier_count=4

# Class patterns
class1="/^$ws*\<\(class\|interface\)\>$ws*$identifier/\2/"
class2="/^[^.*\/]*\($modifier$ws*\)*\<\(class\|interface\)\>$ws*$identifier/\7/"

# Constructor pattern
constructor="/^$ws*\($modifier$ws*\)*$class_type$ws*(/\6/"

# Pattern for methods that return primitive types, e.g.,
#
#   int[] foo()
#
method1="/^[^.*\/]*$primitive_type$ws*\(\[$ws*\]$ws*\)*$identifier$ws*(/\4/"

# Pattern for methods that return class types, e.g.,
#
#   Foo[] foo()
#
method2="/^[^.*\/]*$class_type$ws*\(\[$ws*\]$ws*\)*$identifier$ws*(/\3/"

# Pattern for matching primitive variable declarations.
var1a=".*$primitive_type_no_void$ws*\(\[$ws*\]$ws*\)*$identifier"
var1b="$ws*\(=\|;\)"
var1="/$var1a$var1b/\4/"

# Pattern for matching user-defined variable declarations.
var2a=".*$class_type$ws*\(\[$ws*\]$ws*\)*$identifier"
var2b="$ws*\(=\|;\)"
var2="/$var2a$var2b/\3/"

# Delete the old TAGS file.
# Note: the old file must be deleted because we have to run
# etags in append mode. If we don't remove the old file, 
# etags will append everything to the old file.

if [ -f ${java_dir}/TAGS ]; then
    rm ${java_dir}/TAGS
    echo "Removed old TAGS file."
fi

# Use find to recurse through the source hierarchy, 
# finding every java source file.
# Use xargs to apply etags to the source files.
# Note that xargs may invoke etags multiple
# times, depending on how many files it can batch
# per invocation. That is why we run etags in
# append (-a) mode.

echo "Tagging classes and constructors"
find $java_dir \( -name RCS -prune \) -o \( -name CVS -prune \) -o \( -name '*.java' -print \) | xargs  \
"${etags_dir}etags"  -l none -a -o ${java_dir}/TAGS  \
"--regex=$class1" "--regex=$class2"  "--regex=$constructor"  

echo "Tagging methods"
find $java_dir \( -name RCS -prune \) -o \( -name CVS -prune \) -o \( -name '*.java' -print \) | xargs  \
"${etags_dir}etags"  -l none -a -o ${java_dir}/TAGS  \
"--regex=$method1" "--regex=$method2"

echo "Tagging variables"
find $java_dir \( -name RCS -prune \) -o \( -name CVS -prune \) -o \( -name '*.java' -print \) | xargs  \
"${etags_dir}etags"  -l none -a -o ${java_dir}/TAGS  \
"--regex=$var1" "--regex=$var2"

# History:
#
# $Log: jtags,v $
# Revision 1.12  2002/09/16 04:53:11  paulk
# Quote path of etags executable to permit inclusion of spaces on Windows. Thanks to Jens Barnow.
#
# Revision 1.11  2001/01/06 05:29:58  paulk
# Add "\." below to the definition of class_type so
# that methods whose return type included a period (e.g, Foo.Bar)
# were tagged:
#
#   class_type="\<\([$capital][a-zA-Z_$digit\.]*\)\>"
#
# Thanks to Charles Rich <rich@merl.com>
#
# Revision 1.10  2000/12/23 04:29:57  paulk
# (1) Added "-l none" to the etags arguments (all four calls) to
# eliminate the additional spurious tags that were coming from etags'
# default java parsing:
#
#     ${etags_dir}etags -l none -a -o ${java_dir}/TAGS \
#
# (2) Added "\/" to the prohibited characters at the start of class2,
# method1 and method2 to prevent comment lines like
#
# // this is a nice interface for catching mice
#
# getting tagged:
#
#     class2="/^[^.*\/]*\($modifier$ws*\)*\<\(class\|interface\)\>$ws*$identifier/\7/"
#
# Thanks to Charles Rich <rich@merl.com>  for these improvements.
#
# Revision 1.9  1999/08/19 10:19:51  paulk
# Added prune clause for RCS.
#
# Revision 1.8  1998/02/19 04:08:24  kinnucan
# More edits to the comments.
#
# Revision 1.7  1998/02/19 03:45:03  kinnucan
# Cleaned up the comments.
#
# Revision 1.6  1998/02/19 03:42:05  kinnucan
# "Kent S. Gordon" <kgor@inetspace.com> contributed the following
# improvements
#
#  - Change some .* expressions to [^.*] to prevent matches
#    in source file comments and functions.
#
#  - Removed . from class_type since declarations should never
#    be for another package.
#
# Thanks Kent.
#
# Revision 1.5  1997/12/03 03:31:29  kinnucan
# Divided tagging process into three passes
# through the source hierarchy to avoid overflowing
# the xargs bugger.
#
# Revision 1.4  1997/10/06 04:48:58  kinnucan
# Replaced existing regular expressions with a new set
# based on those contained in andersl-java-font-lock.el
#
# Revision 1.3  1997/08/26 09:10:44  kinnucan
# Added revision number.
#
# Revision 1.2  1997/08/26 09:02:42  kinnucan
# 1. Exclude RCS directories from tags search.
# 2. Added regular expression for abstract classes.
#
#

# End of jtags script.
