#!/bin/sh
#
# Copyright (c) 2008 by Bruce Blinn
#
# NAME
#	Wc - recursive version of the wc command
#
# SYNOPSIS
#	Wc [-clw] [file | directory ...]
#
# DESCRIPTION
#	This is a recursive version of the wc(1) command.  This
#	command counts the lines, words, and characters in the files
#	similar to the wc(1) command; however, this command also
#	searches subdirectories for files to include in the counts.
#
#	If the command line parameter is a file name, it can contain
#	wildcard characters, but then it must be quoted so the
#	wildcard characters will be processed inside this shell
#	script rather than being expanded into file names on the
#	command line.  For example:
#
#		Wc "directory/*.c"
#
#	The above command will search "directory" and its
#	subdirectories for files that end in ".c" and count the
#	lines, words, and characters in those files.
#
# OPTIONS
#	By default the number of characters, words, and lines will
#	be printed for each file.  The following options can be used
#	select specific values to print.
#
#	-c	Count characters.
#	-l	Count lines.
#	-w	Count words.
#
# RETURN VALUE
#	0	Successful completion.
#	1	Error - see the message written to standard error.
#
####################################################################
CMDNAME=$(basename $0)
USAGE="Usage: $CMDNAME [-clw] [file | directory ...]"
COUNT_LINES=FALSE	# Display the number of lines?
COUNT_WORDS=FALSE	# Display the number of words?
COUNT_CHARS=FALSE	# Display the number of characters?
LINES=			# Current file line count.
WORDS=			# Current file word count.
CHARS=			# Current file character count.
FILENAME=		# Current file name.
TOT_LINES=0		# Cumulative line count.
TOT_WORDS=0		# Cumulative word count.
TOT_CHARS=0		# Cumulative character count.
FILE=			# File name from command line.
DIR=			# Top level directory.
PATTERN=		# File name matching pattern.
TMP=/tmp/tmp.$$		# Temporary file for output of wc.

trap 'rm -f /tmp/*.$$' EXIT

while getopts clw OPT
do
	case $OPT in
		c) COUNT_CHARS=TRUE	;;
		l) COUNT_LINES=TRUE	;;
		w) COUNT_WORDS=TRUE	;;

		\?)	echo "$USAGE" 1>&2
			exit 1
			;;
	esac
done
shift $((OPTIND - 1))

#
# Set default.
#
if [ $COUNT_LINES = FALSE -a \
     $COUNT_WORDS = FALSE -a \
     $COUNT_CHARS = FALSE ]
then
	COUNT_LINES=TRUE
	COUNT_WORDS=TRUE
	COUNT_CHARS=TRUE
fi

for FILE in "${@:-.}"
do
	if [ -d "$FILE" ]; then
		DIR="$FILE"
		PATTERN="*"
	else
		DIR=$(dirname "$FILE")
		PATTERN=$(basename "$FILE")
	fi

	for d in $(find $DIR -type d -follow -print	|
			sed "s%^\./%%"			|
			sort)
	do
		#
		# The standard error of wc is sent to /dev/null to
		# discard the message that is printed when there
		# is no file that matches the pattern.
		#
		wc $d/$PATTERN 2>/dev/null |
			grep -v " total$" >$TMP

		exec <$TMP
		while read LINES WORDS CHARS FILENAME
		do
			if [ "$COUNT_LINES" = "TRUE" ]; then
				TOT_LINES=$((TOT_LINES + $LINES))
				printf "%8s" $LINES
			fi

			if [ "$COUNT_WORDS" = "TRUE" ]; then
				TOT_WORDS=$((TOT_WORDS + $WORDS))
				printf " %8s" $WORDS
			fi

			if [ "$COUNT_CHARS" = "TRUE" ]; then
				TOT_CHARS=$((TOT_CHARS + $CHARS))
				printf " %8s" $CHARS
			fi

			printf "  %s\n" "$FILENAME"
		done
	done
done

#
# Print totals
#
if [ "$COUNT_LINES" = "TRUE" ]; then
	printf "%8s" $TOT_LINES
fi

if [ "$COUNT_WORDS" = "TRUE" ]; then
	printf " %8s" $TOT_WORDS
fi

if [ "$COUNT_CHARS" = "TRUE" ]; then
	printf " %8s" $TOT_CHARS
fi

printf "  Total\n"
