#!/bin/ksh
# genmanstub - Author: Edwin Arneson - $Revision: 1.6 $ - $Date: 2007/02/06 20:56:49 $
#	A script to generate a man page stub from the contents of a shell script.
#	It depends on a standardized series of comments at the beginning of
#	the script being processed as well as some details from $USAGE.
# FORMAT:	genmanstub
# CHANGE HISTORY:
#	070130 EJA 1.1	- Created
#	070206 EJA 1.2	- Added -h flag to publish an HTML version.
#	070206 EJA 1.3	- Added touch commands to set the output file datestamps
#					to match the datestamp on the script file.
#					- Minor tidying.
#	070206 EJA 1.4	- Fixed a problem with the call to manserver
#					- Added handler for missing file(s).
#	070206 EJA 1.5	- Added code to output the options to match the usual
#					format of options in manpages.
#					- Corrected \fR tags to \fP.
#	070206 EJA 1.6	- Removed a bit of test text from the options.
# CALLS:  asdf,qwqr asdg, wi (comment), another
#	awk (to do the heaving lifting)
#	perl
#	$ejadir/bin/manserver (to generate an HTML version from the nroff version)
# CALLED BY:
# SCRIPTS:
# PERMISSIONS:
# HOSTS THIS FILE IS IDENTICAL ON:
# FILES:
# GLOBALS:
# LOCALS:
# COMMANDS:
# INPUT:
# OUTPUT:
#	An \fBnroff\fP man page for each input file is written to \fI$ejadir/manpages/man1/<scriptname>.1\fP.
#	If the -h flag is specified, \fBmanserver\fP is called and it writes the HTML file to \fI/Library/WebServer/Documents/man/<scriptname>.1.html\fP.
# OUTPUT USED BY:
#	The \fBman\fP command to view the generated documentation.
#	The script \fB$ejadir/bin/manserver\fP to generate HTML versions of the manpages.
# EXAMPLES:
# HINTS:
# RESTRICTIONS:
#	1) This script depends on a bunch of specific formatting. In particular, the comment header must
#	have #space to mark section headings and non-section headings must not have a space as the character
#	after the #. Since the comment header has evolved over time, it doesn't handle old information very
#	well, so it is probably better to modify the script being processed than to add special handling
#	to this script.
#	2) There are a couple of specific instances where \fBnroff\fP commands can be included in
#	the comment header, but not very many.
#	3) Since this script can be run on itself, care must be taken to ensure comments that document the
#	script don't also match anything in the comment header. A useful means is to use "##" instead
#	"#" for comments in this script that match section headings.
# WARNINGS:
#	40 - localize not found
#	41 - Man page stub ($ejadir/manpages/man1/$f) already exists. Use -o option, or remove manually.
# BUGS:
# DIAGNOSTICS:
#	-X Nothing.
#	-XX Nothing.
#	-XXX Prints the fields associated with some arrays.
#	-XXXX Prints all the input lines to the second awk command (not including some getline commands that process specific sections).
#		The main entries are marked \fTDEBUG4>>>\fP.
#		Some subsidiary getline entries are marked \fTDEBUG4>>>\fP and some are marked \fTDEBUG4>tag>\fP.
# SEE ALSO:
# ERROR CODES:
#	51 - An unknown option was passed to the script, or syntax of the parameters is wrong.
#	52 - You must specify at least one shell script file to process.
# RCS.SH VERSION: 00008
# RCS INFORMATION:
#         $Id: genmanstub,v 1.6 2007/02/06 20:56:49 earneson Exp $
#     $Author: earneson $
#       $Date: 2007/02/06 20:56:49 $
#   $Revision: 1.6 $
#     $Source: /Users/cvs/scripts/all/Users/earneson/bin/genmanstub,v $
#      $State: Exp $

#######
####### Initialization
#######
# Special check for first parameter of "-x" to turn on tracing of the script execution
if [[ "$1" = "-x" ]] ; then
	set -x
fi

# Find and execute the localization script designed to set common environment variables based name characteristics of the executing computer
binDir=`dirname $0` # get the directory this script is in and check for localize there
if [[ -r "$binDir/localize" ]] ; then
	. $binDir/localize
else
	echo "$0: WARNING 40 - localize not found"
fi

# Ensure these three are set
if [[ -z "$localhost" ]] ; then	localhost="`uname -n`"	; export localhost ; fi
if [[ -z "$awkname" ]] ; then	if [[ -x "/usr/bin/nawk" ]] ; then awkname="nawk" ; else awkname="awk" ; export awkname ; fi ; fi 
if [[ -z "$OStype" ]] ; then	OStype="`uname -s`"		; export OStype ; fi
#######
####### Functions
#######

#######
####### Other variables
#######
#   A script to generate a man page stub from the contents of a shell script.
#   It depends on a standardized series of comments at the beginning of
#   the script being processed as well as some details from $USAGE.

basename=`basename $0`
USAGE="$basename generates man page stubs from the contents of the specified shell script(s).
	\$Revision: 1.6 $ - \$Date: 2007/02/06 20:56:49 $
usage: $basename [-h] [-o] [-x]* [-X]* {scriptfile}+
	{scriptfilel} one or more script filenames to generate manpage stubs for
	<-h> after man pages is generated, create an HTML version using manserver
	<-o> overwrite existing manpage file (default=no overwrite)
	<-x> does 'set -x' (may be used in functions and external script calls)
	<-X> sets debugging level--the number of times -X is specified"
debuglevel=0	# -X: stores the number of times -X is specified (debugging level)
xlevel=0		# -x: stores the number of times -x is specified (for optional "set -x" call in functions) and does 'set -x'
overwrite=""	# -o:
htmlflag=""		# -h:

#######
####### Parse parameters.
#######
while getopts :hoxXz optchar ; do
	if [[ $debuglevel -ge 1 ]] ; then echo ">optchar=$optchar< >OPTARG=$OPTARG> >OPTIND=$OPTIND<" ; fi
	case $optchar in
		h)	htmlflag="true" ;;
		o)	overwrite="true" ;;
		x)  xcmd="$xcmd -x" ; ${xcmd:+set -x} ; let "xlevel=$xlevel + 1" ;; # xcmd stores any -x parameters for passing to other scripts
		X)  Xcmd="$Xcmd -X " ; let "debuglevel=$debuglevel + 1" ;;          # Xcmd stores any -X parameters for passing to other scripts

		z)	echo "$USAGE" >&2
			exit 56
			;;
		*)	if [[ -z "$OPTARG" ]] ; then
				case "$optchar" in
					?)	errflag="-$optchar" ;;
					+?)	errflag="$optchar" ;;
					*)	errflag="unknown1" ;;
				esac
			else
				errflag="$OPTARG"
			fi
			echo "$basename: ERROR 51 - Unknown option >$errflag<" >&2
			echo "$USAGE" >&2
			exit 51
			;;
	esac
done
shift `expr $OPTIND - 1`

#######
####### Additional checks
#######
if [[ -z "$1" ]] ; then
	echo "$basename: ERROR 52 - You must specify at least one shell script file to process." >&2
	echo "$USAGE" >&2
	exit 52
fi

#######
####### Main processing
#######
mandir=$ejadir/manpages/man1
for f in $* ; do
	fbase=`basename "$f"`
	if [[ -r $ejadir/manpages/man1/${fbase}.1 && -z "$overwrite" ]] ; then
		echo "$basename: WARNING 41 - Man page stub ($ejadir/manpages/man1/$f) already exists. Use -o option, or remove manually."
	elif [[ ! -r "$f" ]] ; then
		echo "$basename: WARNING 42 - Can not read the file >$f<. Continuing with the next file (if specified)."
	else
		echo "Processing $f..."
		lsstr1=`ls -l $f`
		lsstr2=`ls -ln $f`

		# Get the modification time of the file in the form: Day Mon  d HH:MM:SS YYYY
		fmodstr=`perl -e '
			use strict;
			use POSIX;

			for my $fname (@ARGV) {
		    	my ($dev, $ino, $mode, $nlink, $uid, $gid, $size, $atime, $mtime) = (lstat($fname))[0,1,2,3,4,5,7,8,9] or warn "can not stat $fname";
			    my $mtime2;
				chop($mtime2=ctime($mtime));
				printf("%s", $mtime2);
			}
		' $f`

		$awkname -v debuglevel=$debuglevel '
			# This awk command massages the comment header of the script to make the processing by the next script easier.
			# It looks for a particular pattern in the comment header and inserts blank lines to seperate the sections.
			BEGIN{
				doneflag=0	# stop processing when we get to the end of the comment header
			}
			{
				ch1=substr($0, 1, 1)
				if( (doneflag==0) && ((ch1=="#") || (ch1==":")) ) {
					# Handle the case where old scripts have : as the first character on the first line
					if(ch1==":") {
						print $0
					}
					else {
						ch2=substr($0, 2, 1)
						ch3=substr($0, 3, 1)
						if((ch2==" ") && (ch3!=" ") && ($2!="Note:") && ($2!="NOTE:") && ($2!="Important")){
							print ""
						}
						print $0
					}
				}
				else {
					# Put a marker in to ensure a while loop processing the comment header does not go beyond it.
					if(doneflag==0) print "#ENDOFHEADER"

					doneflag++
					print $0
				}
			}
		' $f \
		| $awkname -v debuglevel=$debuglevel -v fbase="$fbase" -v lsstr1="$lsstr1" -v lsstr2="$lsstr2" -v fmodstr="$fmodstr" '
			BEGIN{
				warncnt=0		# counter for WARNING messages
				errcnt=0		# counter for ERROR messages
				errnumcnt=0		# counter for ERROR numbers
				chardq=sprintf("%c", 34) # double quote
				charsq=sprintf("%c", 39) # single quote
				callsPcnt=0		# counter for CALLS with path
				callsNPcnt=0	# counter for CALLS with no path
				rcsinfocnt=0	# counter for RCS INFORMATION lines
				inputcnt=0		# counter for INPUT 
				outputcnt=0		# counter for OUTPUT 
				outputusedcnt=0	# counter for OUTPUT USED BY 
				excnt=0			# counter for EXAMPLES
				hintcnt=0		# counter for HINTS
				rescnt=0		# counter for RESTRICTIONS 
				bugscnt=0		# counter for BUGS
				filescnt=0		# counter for FILES
				scriptscnt=0	# counter for SCRIPTS
				hostsidentcnt=0	# counter for HOSTS THIS FILE IS IDENTICAL ON
				globalscnt=0	# counter for GLOBALS
				localscnt=0		# counter for LOCALS
				commandscnt=0	# counter for COMMANDS
				longdescrcnt=0	# counter for DESCRIPTION
				argucnt=0		# counter for ARGUMENTS
				optcnt=0		# counter for OPTIONS
				diagcnt=0		# counter for DIAGNOSTICS
				calledbycnt=0	# counter for CALLED BY
				seealsocnt=0	# counter for SEE ALSO

				# Extract some information from the files ls info
				lscnt1=split(lsstr1, lsarr1)
				lscnt2=split(lsstr2, lsarr2)
				if(debuglevel >= 3) {
					printf("DEBUG3> ls -l: ")
					for(d=1 ; d<= lscnt1 ; d++) printf("%d=[%s] ", d, lsarr1[d])
					print ""
					printf("DEBUG3> ls -ln: ")
					for(d=1 ; d<= lscnt2 ; d++) printf("%d=[%s] ", d, lsarr2[d])
					print ""
				}
				if(lsarr2[3] >= 100) uid="userUID" ; else uid=lsarr1[3]
				if(lsarr2[4] >= 100) gid="userGID" ; else gid=lsarr1[4]
				perm=substr(lsarr1[1], 2)
			}
			{
				if(debuglevel >= 4) printf("DEBUG4>>>%s\n", $0)
				if(index($0, "DEBUG")==1) next


				## DOCUMENTED VERSION
				## DESCRIPTION
				i=1
				## lismeta - Author: Edwin Arneson - $Revision: 1.6 $ - $Date: 2007/02/06 20:56:49 $
				## leaseinfo - Author: Edwin Arneson - $Revision: 1.6 $ - $Date: 2007/02/06 20:56:49 $
				## : chall[.sh] - Author: Edwin Arneson - version 0.06 - June 17, 1991
				if(($1=="#" || $1==":") && $3=="-" && $4=="Author:") {
					split($0, inarr, "-")

					# Get the author
					split(inarr[2], inarrf2, ":")
					author=inarrf2[2]
					while(index(author, " ")==1) author=substr(author, 2)										# Delete leading spaces
					while(index(author, " ")==length(author)) { author=substr(author, 1, length(author)-1) }	# Delete trailing space

					# Get the file version
					f3cnt=split(inarr[3], inarrf3, "[: ]")
					# we should end up with one of 3 forms:
					# 1="" 2="$Revision" 3="" 4=<ver#> 5="$" 6=""
					# 1="" 2="$Revision: 1.6 $" 3=""
					# 1="" 2="version" 3=<ver#>
					if(debuglevel >= 3) {
						printf("DEBUG3> revision: ")
						for(d=1 ; d<= f3cnt ; d++) printf("%d=[%s] ", d, inarrf3[d])
						print ""
					}
					if(inarrf3[2]=="$Revision" && inarrf3[4]!="") 
						revstr=inarrf3[4]
					else if (inarrf3[2]=="version")
						revstr=inarrf3[3]

					# Get the file date
					f4cnt=split(inarr[4], inarrf4, "[: ]")
					# we should end up with one of 3 forms:
					# 1="" 2="$Date" 3="" 4="YYYY/MM/DD" 5="HH" 6="MM" 7="SS" 8="$"
					# 1="" 2="$Date: 2007/02/06 20:56:49 $"
					# 1="" 2="Mon" 3="dd," 4="YYYY"
					if(debuglevel >= 3) {
						printf("DEBUG3> date: ")
						for(d=1 ; d<= f4cnt ; d++) printf("%d=[%s] ", d, inarrf4[d])
						print ""
					}
					if(inarrf4[2]=="$Date" && inarrf4[8]=="$")
						datestr=inarrf4[4] " " inarrf4[5] ":" inarrf4[6] ":" inarrf4[7] 
					else if ($inarrf4[2]=="$Date: 2007/02/06 20:56:49 $")
						inarrf4[1]=inarrf4[1] # NOOP
					else if (index(inarrf4[3], ",")==length(inarrf4[3])) # second field ends with a comma
						datestr=inarrf4[2] " " inarrf4[3] " " inarrf4[4]

					# All the rest of the lines until the FORMAT line is the description.
					# Note: While the FORMAT line used to contain the SYNOPSIS, it does not any more. However, very old scripts
					#		may still have the SYNOPSIS here, so we will collect it, too.
					getline ; if(debuglevel >= 4) printf("DEBUG4>>>%s\n", $0)
					while ($2 != "FORMAT:" && $1 != "#ENDOFHEADER" ) {
						longdescrcnt++
						longdescrarr[longdescrcnt]=substr($0, 2)
						getline ; if(debuglevel >= 4) printf("DEBUG4>>>%s\n", $0)
					}
					if($2 == "FORMAT:" && $3 != "") {
						synopstr=$3
						for(i=4 ; i<= NF ; i++)
							synopstr=synopstr " " $i
					}
				}

				# Short description for the NAME section
				# USAGE="$basename displays raw or processed output from metastat.
				if(index($0, "USAGE=")==1) {
					shortdescr=$2
					for(i=3 ; i<= NF ; i++)
						shortdescr=shortdescr " " $i
				}

				## WARNINGS
				# echo "$0: WARNING 40 - localize not found"
				if($1=="echo" && $3=="WARNING") {
					warncnt++
					warnarr[warncnt,1]=$4
					pos=index($0, "-")
					warnarr[warncnt,2]=substr($0, pos)
					pos=index(warnarr[warncnt,2], chardq)
					warnarr[warncnt,2]=substr(warnarr[warncnt,2], 1, pos-1)
				}

				## ERROR CODES
				# 1) find error messages in the comment header
				## echo "$basename: ERROR 51 - Unknown option >$errflag<" >&2
				if($1=="#" && $2=="ERROR" && $3=="CODES:") {
					getline ; if(debuglevel >= 4) printf("DEBUG4>err1>%s\n", $0)
					while($1 != "") {
						errcnt++
						errarr[errcnt,1]=$2
						pos=index($0, "-")
						errarr[errcnt,2]=substr($0, pos)

						# track the error numbers
						if(errnumhash[$2]=="") {
							errnumhash[$2]=$2
							errnumcnt++
							errnumarr[errnumcnt]=$2
						}

						getline ; if(debuglevel >= 4) printf("DEBUG4>err2>%s\n", $0)
					}
				}
				# 2) find error messages in the code
				if($1=="echo" && $3=="ERROR") {
					errcnt++
					errarr[errcnt,1]=$4
					pos=index($0, "-")
					errarr[errcnt,2]=substr($0, pos)
					pos=index(errarr[errcnt,2], chardq)
					errarr[errcnt,2]=substr(errarr[errcnt,2], 1, pos-1)

					# track the error numbers
					if(errnumhash[$4]=="") {
						errnumhash[$4]=$4
						errnumcnt++
						errnumarr[errnumcnt]=$4
					}
				}

				## CALLS
				if($1=="#" && $2=="CALLS:") {
					if($3!="") {
						# It is not unusual for the commands to be a comma seperated list, as well
						# sometimes there are comments in parenthesis. This code does not handle
						# the case where there is a comma in the comment.
						ccnt=split(substr($0, 10), carr, ",")

						# Check the CALLS line for command names
						for(i=1 ; i<= ccnt ; i++) {
							# With a path
							if(index(carr[i], "/") > 0) {
								callsPcnt++
								callsParr[callsPcnt]=carr[i]
							}
							# No path
							else {
								callsNPcnt++
								callsNParr[callsNPcnt]=carr[i]
							}
						}
					}

					# Check the lines following the CALLS line for command names
					getline ; if(debuglevel >= 4) printf("DEBUG4>>>%s\n", $0)
					while ($1!="") {
						ccnt=split(substr($0, 3), carr, ",")
						# gsub(",", " ")
						# for(i=2 ; i<= NF ; i++) {
						for(i=1 ; i<= ccnt ; i++) {
							# With a path
							if(index(carr[i], "/") > 0) {
								callsPcnt++
								callsParr[callsPcnt]=carr[i]
							}
							# No path
							else {
								callsNPcnt++
								callsNParr[callsNPcnt]=carr[i]
							}
						}
						getline ; if(debuglevel >= 4) printf("DEBUG4>>>%s\n", $0)
					}
				} # end CALLS:

				if($1=="#" && $2=="RCS.SH")
					rcsshver=$4

				if($1=="#" && $2=="RCS" && $3=="INFORMATION:") {
					getline ; if(debuglevel >= 4) printf("DEBUG4>rcsi1>%s\n", $0)
					while ($1!="" && $1 != "#ENDOFHEADER") {
						rcsinfocnt++
						rcsinfoarr[rcsinfocnt]=substr($0, 3)
						getline ; if(debuglevel >= 4) printf("DEBUG4>rcsi2>%s\n", $0)
					}
				} # RCS INFORMATION:

				if($1=="#" && $2=="FILES:") {
					if($3!="") { pos=index($0, ":") ; filescnt++ ; filesarr[filescnt]=substr($0, pos+2) }
					getline
					while ($1!="") { filescnt++ ; filesarr[filescnt]=substr($0, 2) ; getline }
				}
				if($1=="#" && $2=="SCRIPTS:") {
					if($3!="") { pos=index($0, ":") ; scriptscnt++ ; scriptsarr[scriptscnt]=substr($0, pos+2) }
					getline
					while ($1!="") { scriptscnt++ ; scriptsarr[scriptscnt]=substr($0, 2) ; getline }
				}
				if($1=="#" && $2=="HOSTS" && $3=="THIS" && $4=="FILE") {
					if($8!="") { pos=index($0, ":") ; hostsidentcnt++ ; hostsidentarr[hostsidentcnt]=substr($0, pos+2) }
					getline ; if(debuglevel >= 4) printf("DEBUG4>hio1>%s\n", $0)
					while ($1!="") { hostsidentcnt++ ; hostsidentarr[hostsidentcnt]=substr($0, 2) ; getline ; if(debuglevel >= 4) printf("DEBUG4>hio2>%s\n", $0) }
				}
				if($1=="#" && $2=="GLOBALS:") {
					if($3!="") { pos=index($0, ":") ; globalscnt++ ; globalsarr[globalscnt]=substr($0, pos+2) }
					getline
					while ($1!="") { globalscnt++ ; globalsarr[globalscnt]=substr($0, 2) ; getline }
				}
				if($1=="#" && $2=="LOCALS:") {
					if($3!="") { pos=index($0, ":") ; localscnt++ ; localsarr[localscnt]=substr($0, pos+2) }
					getline
					while ($1!="") { localscnt++ ; localsarr[localscnt]=substr($0, 2) ; getline }
				}
				if($1=="#" && $2=="COMMANDS:") {
					if($3!="") { pos=index($0, ":") ; commandscnt++ ; commandsarr[commandscnt]=substr($0, pos+2) }
					getline
					while ($1!="") { commandscnt++ ; commandsarr[commandscnt]=substr($0, 2) ; getline }
				}

				if($1=="#" && $2=="INPUT:") {
					if($3!="") { pos=index($0, ":") ; inputcnt++ ; inputarr[inputcnt]=substr($0, pos+2) }
					getline
					while ($1!="") { inputcnt++ ; inputarr[inputcnt]=substr($0, 2) ; getline }
				}
				if($1=="#" && $2=="OUTPUT:") {
					if($3!="") { pos=index($0, ":") ; outputcnt++ ; outputarr[outputcnt]=substr($0, pos+2) }
					getline ; if(debuglevel >= 4) printf("DEBUG4>o1>%s\n", $0)
					while ($1!="") { outputcnt++ ; outputarr[outputcnt]=substr($0, 2) ; getline ; if(debuglevel >= 4) printf("DEBUG4>o2>%s\n", $0) }
				}
				if($1=="#" && $2=="OUTPUT" && $3=="USED") {
					if($5!="") { pos=index($0, ":") ; outputusedcnt++ ; outputusedarr[outputusedcnt]=substr($0, pos+2) }
					getline ; if(debuglevel >= 4) printf("DEBUG4>oub1>%s\n", $0)
					while ($1!="") { outputusedcnt++ ; outputusedarr[outputusedcnt]=substr($0, 2) ; getline ; if(debuglevel >= 4) printf("DEBUG4>oub2>%s\n", $0) }
				}
				if($1=="#" && $2=="EXAMPLES:") {
					if($3!="") { pos=index($0, ":") ; excnt++ ; exarr[excnt]=substr($0, pos+2) }
					getline
					while ($1!="") { excnt++ ; exarr[excnt]=substr($0, 2) ; getline }
				}
				if($1=="#" && $2=="HINTS:") {
					if($3!="") { pos=index($0, ":") ; hintcnt++ ; hintarr[hintcnt]=substr($0, pos+2) }
					getline
					while ($1!="") { hintcnt++ ; hintarr[hintcnt]=substr($0, 2) ; getline }
				}
				if($1=="#" && $2=="RESTRICTIONS:") {
					if($3!="") { pos=index($0, ":") ; rescnt++ ; resarr[rescnt]=substr($0, pos+2) }
					getline
					while ($1!="") { rescnt++ ; resarr[rescnt]=substr($0, 2) ; getline }
				}
				if($1=="#" && $2=="BUGS:") {
					if($3!="") { pos=index($0, ":") ; bugscnt++ ; bugsarr[bugscnt]=substr($0, pos+2) }
					getline
					while ($1!="") { bugscnt++ ; bugsarr[bugscnt]=substr($0, 2) ; getline }
				}
				if($1=="#" && $2=="DIAGNOSTICS:") {
					if($3!="") { pos=index($0, ":") ; diagcnt++ ; diagarr[diagcnt]=substr($0, pos+2) }
					getline
					while ($1!="") { diagcnt++ ; diagarr[diagcnt]=substr($0, 2) ; getline }
				}
				if($1=="#" && $2=="CALLED" && $3=="BY:") {
					if($4!="") { pos=index($0, ":") ; calledbycnt++ ; calledbyarr[calledbycnt]=substr($0, pos+2) }
					getline ; if(debuglevel >= 4) printf("DEBUG4>cb1>%s\n", $0)
					while ($1!="") { calledbycnt++ ; calledbyarr[calledbycnt]=substr($0, 2) ; getline ; if(debuglevel >= 4) printf("DEBUG4>cb2>%s\n", $0) }
				}
				if($1=="#" && $2=="SEE" && $3=="ALSO:") {
					if($4!="") { pos=index($0, ":") ; seealsocnt++ ; seealsoarr[seealsocnt]=substr($0, pos+2) }
					getline ; if(debuglevel >= 4) printf("DEBUG4>sa1>%s\n", $0)
					while ($1!="") { seealsocnt++ ; seealsoarr[seealsocnt]=substr($0, 2) ; getline ; if(debuglevel >= 4) printf("DEBUG4>sa2>%s\n", $0) }
				}

				## SYNOPSIS
				## ARGUMENTS
				## OPTIONS
				if($1=="usage:") {
					# usage: $basename [[-S] | [-h | -p -i -tt -s setname]] [-x]* [-X]*
					synopstr=fbase
					for(i=3 ; i<= NF ; i++)
						synopstr=synopstr " " $i
					if(index($0, chardq) == 0) {
						while(index($0, chardq) == 0) {	# we should be in a quoted string at this point, so scan until we see a double quote
							# cases to handle
							# {scriptfilel} one or more script filenames to generate manpage stubs for
							# <-w asdf> this is a test
							# <-h> after man pages is generated, create an HTML version using manserver
							getline ; if(debuglevel >= 4) printf("DEBUG4>d>%s\n", $0)
							if(index($1, "<")==1) {
								# cases to handle:
								# <-w asdf> this is a test
								# <-h> after man pages is generated, create an HTML version using manserver
								pos1=index($0, "<")
								pos2=index($0, ">")
								optcnt++
								optarr[optcnt,1]=substr($0, pos1+1, 2)	# get the 2 characters of the option
								# check for parameters for the option
								if(pos2-3 != pos1)
									optarr[optcnt,2]=substr($0, pos1+4, pos2-pos1-4)
								optarr[optcnt,3]=substr($0, pos2+2)
							}
							else {
								# case to handle:
								# {scriptfilel} one or more script filenames to generate manpage stubs for
								argucnt++
								arguarr[argucnt]=$0
							}
						}
					}
				}

				## CHANGE HISTORY - just get date and version strings if necessary
				##   000822 EJA 1.1  - Created
				##   020704 EJA 1.1  - Check a second location for metastat.
				# if(revstr=="" || author=="" || datestr=="") 
				if($1=="#" && $2=="CHANGE" && $3=="HISTORY:") {
					revstrsave=revstr
					authorsave=author
					datestrsave=datestr
					getline ; if(debuglevel >= 4) printf("DEBUG4>a>%s\n", $0)
					while($1!="") {
						if($1=="#" && $5=="-" ) {
							datestr=$2
							author=$3
							revstr=$4
						}
						getline ; if(debuglevel >= 4) printf("DEBUG4>b>%s\n", $0)
					}
					if(authorsave!="") author=authorsave

					if(revstrsave!="" && revstrsave >= revstr) {
						revstr=revstrsave
						datestr=datestrsave
					}
				}

				## $Id: genmanstub,v 1.6 2007/02/06 20:56:49 earneson Exp $
				##         $Id: genmanstub,v 1.6 2007/02/06 20:56:49 earneson Exp $
				if($1=="#" && $2=="$Id:") {
					if(rcsinfocnt==0) {
						rcsinfocnt++
						rcsinfoarr[rcsinfocnt]=substr($0, 3)
					}
					if(revstr=="") revstr=$4
					if(datestr=="") datestr=$5 " " $6
					if(author=="") author=$7
				}

			}

			END{
				printf(".TH %s 1 %cEJA UTILITY%c\n", fbase, 34, 34)
				printf(".nrLL 75n\n")
				printf(".UC 4\n")
				printf(".ta 4 8 12 16 20 24 28 32 36 40\n")
				printf(".SH NAME\n")
				printf("%s - %s\n", fbase, shortdescr)

				if(datestr=="") datestr=fmodstr	# if the contents of the file did not set datestr, use the datestamp of the file itself
				printf(".SH DOCUMENTED VERSION\n")
				printf("%s - %s\n", revstr, datestr)

				printf(".SH SYNOPSIS\n")
				if(synopstr=="")
					printf("%s\n", fbase)
				else
					printf("%s\n", synopstr)


				if(longdescrcnt >0) { printf(".SH DESCRIPTION\n") ; for(i=1 ; i<= longdescrcnt ; i++) printf("%s\n.br\n", longdescrarr[i]) }
				if(argucnt >0) { printf(".SH ARGUMENTS\n") ; for(i=1 ; i<= argucnt ; i++) printf("%s\n.br\n", arguarr[i]) }

				if(optcnt >0) { 
					printf(".SH OPTIONS\n")
					for(i=1 ; i<= optcnt ; i++) {
						printf(".TP\n")	# tagged list element
						printf("\\fB%s\\fP", optarr[i,1]) 
						if(optarr[i,2]=="")
							printf("\n")
						else
							printf(" \\fI%s\\fP\n", optarr[i,2])
						printf("%s\n.br\n", optarr[i,3]) 
					}
				}

				if(filescnt >0) { printf(".SH FILES\n") ; for(i=1 ; i<= filescnt ; i++) printf("%s\n.br\n", filesarr[i]) }
				if(scriptscnt >0) { printf(".SH SCRIPTS\n") ; for(i=1 ; i<= scriptscnt ; i++) printf("%s\n.br\n", scriptsarr[i]) }
				if(hostsidentcnt >0) { printf(".SH HOSTS THIS FILE IS IDENTICAL ON\n") ; for(i=1 ; i<= hostsidentcnt ; i++) printf("%s\n.br\n", hostsidentarr[i]) }
				if(globalscnt >0) { printf(".SH GLOBALS\n") ; for(i=1 ; i<= globalscnt ; i++) printf("%s\n.br\n", globalsarr[i]) }
				if(localscnt >0) { printf(".SH LOCALS\n") ; for(i=1 ; i<= localscnt ; i++) printf("%s\n.br\n", localsarr[i]) }
				if(commandscnt >0) { printf(".SH COMMANDS\n") ; for(i=1 ; i<= commandscnt ; i++) printf("%s\n.br\n", commandsarr[i]) }

				if(inputcnt >0) { printf(".SH INPUT\n") ; for(i=1 ; i<= inputcnt ; i++) printf("%s\n.br\n", inputarr[i]) }

				if(outputcnt > 0) {
					# do some extra processing to allow .nf/.fi NROFF tags (these tags map to <PRE> & </PRE> HTML tags)
					printf(".SH OUTPUT\n")
					brstr=".br"
					for(i=1 ; i<= outputcnt ; i++) {
						outfieldcnt=split(outputarr[i], outfieldsarr)
						if(debuglevel >= 3) {
							printf("DEBUG3> outfieldsarr: ")
							for(d=1 ; d<= outfieldcnt ; d++) printf("%d=[%s] ", d, outfieldsarr[d])
							print ""
						}
						# Look for a couple of NROFF tags and do special handling if they are found
						 	if(outfieldsarr[1]==".nf") { printf("%s\n", outfieldsarr[1]) ; brstr="" }
						else if(outfieldsarr[1]==".fi") { printf("%s\n", outfieldsarr[1]) ; brstr=".br" }
						else                            { printf("%s\n", outputarr[i]) ; if(brstr!="") printf("%s\n", brstr) }
					}
				}

				if(outputusedcnt >0) { printf(".SH OUTPUT USED BY\n") ; for(i=1 ; i<= outputusedcnt ; i++) printf("%s\n.br\n", outputusedarr[i]) }
				if(excnt >0) { printf(".SH EXAMPLES\n") ; for(i=1 ; i<= excnt ; i++) printf("%s\n.br\n", exarr[i]) }
				if(hintcnt >0) { printf(".SH HINTS\n") ; for(i=1 ; i<= hintcnt ; i++) printf("%s\n.br\n", hintarr[i]) }
				if(rescnt >0) { printf(".SH RESTRICTIONS\n") ; for(i=1 ; i<= rescnt ; i++) printf("%s\n.br\n", resarr[i]) }
				if(bugscnt >0) { printf(".SH BUGS\n") ; for(i=1 ; i<= bugscnt ; i++) printf("%s\n.br\n", bugsarr[i]) }

				printf(".SH RCS.SH VERSION\n")
				if(rcsshver=="")
					print "unknown"
				else
					print rcsshver
				printf(".SH RCS INFORMATION\n")

				for(i=1 ; i<= rcsinfocnt ; i++) printf("%s\n.br\n", rcsinfoarr[i])

				# \fB=bold \fI=italics \fR=roman \fT=teletype \fP=return to previous
				printf(".SH PERMISSIONS\n\\fT %s %s %s\\fR\n", perm, uid, gid)

				if(warncnt >0) {
					printf(".SH WARNING(S)\n")
					for(i=1 ; i<= warncnt ; i++) {
						printf("%d %s\n", warnarr[i,1], warnarr[i,2])
						if(i < warncnt) printf(".br\n")
					}
				}

				## ERROR CODES==EXIT STATUS
				if(errcnt >0) {
					if(debuglevel >= 3) {
						print "DEBUG3> errnumcnt=" errnumcnt, "errcnt=", errcnt
						for(i=1 ; i<= errnumcnt ; i++)
							print "DEBUG3> errnumarr[" i "]=" errnumarr[i]
						for(j=1 ; j<= errcnt ; i++) {
							print "DEBUG3> errarr[" i ",1]=" errarr[i,1], "errarr[" i ",2]=" errarr[i,2]
						}
					}
					printf(".SH EXIT STATUS\n")

					outcnt=0	# track the processing of error messages do not output a .br after the last one
					# Output the error codes in numeric order
					for(i=1 ; i<= errnumcnt ; i++) {
						currnum=errnumarr[i]
						for(j=1 ; j<= errcnt ; j++) {
							if(errarr[j,1]==currnum) {
								dupmessage=0
								# Scan back through the previous message and do not print exact duplicates
								for(k=j-1 ; k>= 1 ; k--) {
									if(errarr[j,1]==errarr[k,1] && errarr[j,2]==errarr[k,2])
										dupmessage++
								}
								if(dupmessage==0) {
									outcnt++
									if(outcnt >1) printf(".br\n")
									printf("%d %s\n", errarr[j,1], errarr[j,2])
								}
							}
						}
					}

#					for(i=1 ; i<= errcnt ; i++) {
#						printf("%d %s\n", errarr[i,1], errarr[i,2])
#						if(i < errcnt) printf(".br\n")
#					}
				}

				if(callsNPcnt >0 || callsPcnt >0) {
					printf(".SH CALLS\n")
					if(callsNPcnt >= 1)
						printf("%s", callsNParr[1])
					for(i=2 ; i<= callsNPcnt ; i++)
						printf(", %s", callsNParr[i])
					if(callsNPcnt >= 1)
						printf("\n.br\n")
	
					for(i=1 ; i<= callsPcnt ; i++) {
						printf("%s\n.br\n", callsParr[i])
					}
				}

				if(calledbycnt >0) { printf(".SH CALLED BY\n") ; for(i=1 ; i<= calledbycnt ; i++) printf("%s\n.br\n", calledbyarr[i]) }
				if(seealsocnt >0) { printf(".SH SEE ALSO\n") ; for(i=1 ; i<= seealsocnt ; i++) printf("%s\n.br\n", seealsoarr[i]) }

				if(author=="") author="Unknown"
				printf(".SH AUTHOR\n%s\n", author)

				if(diagcnt >0) {
					printf(".SH DIAGNOSTICS\n")
					for(i=1 ; i<= diagcnt ; i++) {
						if(index(diagarr[i], "-X")>0) {
							fieldcnt=split(diagarr[i], fieldarr)
							printf(".TP\n")	# tagged list element
							printf("\\fB%s\\fP\n", fieldarr[1])
							printf("%s", fieldarr[2])
							for(j=3 ; j<= fieldcnt ; j++)
								printf(" %s", fieldarr[j])
							printf("\n.br\n")
						}
						else {
							fieldcnt=split(diagarr[i], fieldarr)
							printf("%s", fieldarr[1])
							for(j=2 ; j<= fieldcnt ; j++)
								printf(" %s", fieldarr[j])
							printf("\n.br\n")
						}
					}
				}

				printf(".lp\n")
				printf(".hl\n")
			}
		' >${mandir}/${fbase}.1

		# Set the manpage file datestamp to match the datestamp on the script file
		touch -r $f ${mandir}/${fbase}.1

		# Generate HTML version if requested.
		if [[ -n "$htmlflag" ]] ; then
			(
				cd $mandir
				echo $echoflag "$basename: generating HTML manpage using manserver... \c"
				$ejadir/bin/manserver ${fbase}.1 >/Library/WebServer/Documents/man/${fbase}.1.html
			)
			touch -r $f /Library/WebServer/Documents/man/${fbase}.1.html
		fi
	fi
done

#######
####### Cleanup
#######

#######
####### The end.
#######
exit
