1#! /bin/sh
2
3# Copyright (C) 1995-2005 The Free Software Foundation, Inc.
4
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2, or (at your option)
8# any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14
15# RCS to ChangeLog generator
16
17# Generate a change log prefix from RCS files (perhaps in the CVS repository)
18# and the ChangeLog (if any).
19# Output the new prefix to standard output.
20# You can edit this prefix by hand, and then prepend it to ChangeLog.
21
22# Ignore log entries that start with `#'.
23# Clump together log entries that start with `{topic} ',
24# where `topic' contains neither white space nor `}'.
25
26Help='The default FILEs are the files registered under the working directory.
27Options:
28
29  -c CHANGELOG  Output a change log prefix to CHANGELOG (default ChangeLog).
30  -h HOSTNAME  Use HOSTNAME in change log entries (default current host).
31  -i INDENT  Indent change log lines by INDENT spaces (default 8).
32  -l LENGTH  Try to limit log lines to LENGTH characters (default 79).
33  -L FILE  Use rlog-format FILE for source of logs.
34  -R  If no FILEs are given and RCS is used, recurse through working directory.
35  -r OPTION  Pass OPTION to subsidiary log command.
36  -t TABWIDTH  Tab stops are every TABWIDTH characters (default 8).
37  -u "LOGIN<tab>FULLNAME<tab>MAILADDR"  Assume LOGIN has FULLNAME and MAILADDR.
38  -v  Append RCS revision to file names in log lines.
39  --help  Output help.
40  --version  Output version number.
41
42Report bugs to <bug-gnu-emacs@gnu.org>.'
43
44Id='$Id: rcs2log,v 1.48 2001/09/05 23:07:46 eggert Exp $'
45
46# Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2001, 2003
47#  Free Software Foundation, Inc.
48
49# This program is free software; you can redistribute it and/or modify
50# it under the terms of the GNU General Public License as published by
51# the Free Software Foundation; either version 2, or (at your option)
52# any later version.
53#
54# This program is distributed in the hope that it will be useful,
55# but WITHOUT ANY WARRANTY; without even the implied warranty of
56# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
57# GNU General Public License for more details.
58#
59# You should have received a copy of the GNU General Public License
60# along with this program; see the file COPYING.  If not, write to the
61# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
62# Boston, MA 02111-1307, USA.
63
64Copyright='Copyright 1992-2003 Free Software Foundation, Inc.
65This program comes with NO WARRANTY, to the extent permitted by law.
66You may redistribute copies of this program
67under the terms of the GNU General Public License.
68For more information about these matters, see the files named COPYING.
69Author: Paul Eggert <eggert@twinsun.com>'
70
71# functions
72@MKTEMP_SH_FUNCTION@
73
74# Use the traditional C locale.
75LANG=C
76LANGUAGE=C
77LC_ALL=C
78LC_COLLATE=C
79LC_CTYPE=C
80LC_MESSAGES=C
81LC_NUMERIC=C
82LC_TIME=C
83export LANG LANGUAGE LC_ALL LC_COLLATE LC_CTYPE LC_MESSAGES LC_NUMERIC LC_TIME
84
85# These variables each contain a single ASCII character.
86# Unfortunately, there's no portable way of writing these characters
87# in older Unix implementations, other than putting them directly into
88# this text file.
89SOH='' # SOH, octal code 001
90tab='	'
91nl='
92'
93
94# Parse options.
95
96# defaults
97: ${MKTEMP="@MKTEMP@"}
98: ${AWK=awk}
99: ${TMPDIR=/tmp}
100
101changelog=ChangeLog # change log file name
102datearg= # rlog date option
103hostname= # name of local host (if empty, will deduce it later)
104indent=8 # indent of log line
105length=79 # suggested max width of log line
106logins= # login names for people we know fullnames and mailaddrs of
107loginFullnameMailaddrs= # login<tab>fullname<tab>mailaddr triplets
108logTZ= # time zone for log dates (if empty, use local time)
109recursive= # t if we want recursive rlog
110revision= # t if we want revision numbers
111rlog_options= # options to pass to rlog
112rlogfile= # log file to read from
113tabwidth=8 # width of horizontal tab
114
115while :
116do
117	case $1 in
118	-c)	changelog=${2?}; shift;;
119	-i)	indent=${2?}; shift;;
120	-h)	hostname=${2?}; shift;;
121	-l)	length=${2?}; shift;;
122	-L)	rlogfile=${2?}; shift;;
123	-[nu])	# -n is obsolescent; it is replaced by -u.
124		case $1 in
125		-n)	case ${2?}${3?}${4?} in
126			*"$tab"* | *"$nl"*)
127				echo >&2 "$0: -n '$2' '$3' '$4': tabs, newlines not allowed"
128				exit 1;;
129			esac
130			login=$2
131			lfm=$2$tab$3$tab$4
132			shift; shift; shift;;
133		-u)
134			# If $2 is not tab-separated, use colon for separator.
135			case ${2?} in
136			*"$nl"*)
137				echo >&2 "$0: -u '$2': newlines not allowed"
138				exit 1;;
139			*"$tab"*)
140				t=$tab;;
141			*)
142				t=':';;
143			esac
144			case $2 in
145			*"$t"*"$t"*"$t"*)
146				echo >&2 "$0: -u '$2': too many fields"
147				exit 1;;
148			*"$t"*"$t"*)
149				uf="[^$t]*$t" # An unselected field, followed by a separator.
150				sf="\\([^$t]*\\)" # The selected field.
151				login=`expr "X$2" : "X$sf"`
152				lfm="$login$tab"`
153					expr "X$2" : "$uf$sf"
154				  `"$tab"`
155					expr "X$2" : "$uf$uf$sf"
156				`;;
157			*)
158				echo >&2 "$0: -u '$2': not enough fields"
159				exit 1;;
160			esac
161			shift;;
162		esac
163		case $logins in
164		'') logins=$login;;
165		?*) logins=$logins$nl$login;;
166		esac
167		case $loginFullnameMailaddrs in
168		'') loginFullnameMailaddrs=$lfm;;
169		?*) loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$lfm;;
170		esac;;
171	-r)
172		case $rlog_options in
173		'') rlog_options=${2?};;
174		?*) rlog_options=$rlog_options$nl${2?};;
175		esac
176		shift;;
177	-R)	recursive=t;;
178	-t)	tabwidth=${2?}; shift;;
179	-v)	revision=t;;
180	--version)
181		set $Id
182		rcs2logVersion=$3
183		echo >&2 "rcs2log (GNU Emacs) $rcs2logVersion$nl$Copyright"
184		exit 0;;
185	-*)	echo >&2 "Usage: $0 [OPTION]... [FILE ...]$nl$Help"
186		case $1 in
187		--help) exit 0;;
188		*) exit 1;;
189		esac;;
190	*)	break;;
191	esac
192	shift
193done
194
195month_data='
196	m[0]="Jan"; m[1]="Feb"; m[2]="Mar"
197	m[3]="Apr"; m[4]="May"; m[5]="Jun"
198	m[6]="Jul"; m[7]="Aug"; m[8]="Sep"
199	m[9]="Oct"; m[10]="Nov"; m[11]="Dec"
200'
201
202logdir=`$MKTEMP -d $TMPDIR/rcs2log.XXXXXX`
203test -n "$logdir" || exit
204llogout=$logdir/l
205trap exit 1 2 13 15
206trap "rm -fr $logdir 2>/dev/null" 0
207
208# If no rlog-format log file is given, generate one into $rlogfile.
209case $rlogfile in
210'')
211	rlogfile=$logdir/r
212
213	# If no rlog options are given,
214	# log the revisions checked in since the first ChangeLog entry.
215	# Since ChangeLog is only by date, some of these revisions may be duplicates of
216	# what's already in ChangeLog; it's the user's responsibility to remove them.
217	case $rlog_options in
218	'')
219		if test -s "$changelog"
220		then
221			e='
222				/^[0-9]+-[0-9][0-9]-[0-9][0-9]/{
223					# ISO 8601 date
224					print $1
225					exit
226				}
227				/^... ... [ 0-9][0-9] [ 0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9]+ /{
228					# old-fashioned date and time (Emacs 19.31 and earlier)
229					'"$month_data"'
230					year = $5
231					for (i=0; i<=11; i++) if (m[i] == $2) break
232					dd = $3
233					printf "%d-%02d-%02d\n", year, i+1, dd
234					exit
235				}
236			'
237			d=`$AWK "$e" <"$changelog"` || exit
238			case $d in
239			?*) datearg="-d>$d";;
240			esac
241		fi;;
242	esac
243
244	# Use TZ specified by ChangeLog local variable, if any.
245	if test -s "$changelog"
246	then
247		extractTZ='
248			/^.*change-log-time-zone-rule['"$tab"' ]*:['"$tab"' ]*"\([^"]*\)".*/{
249				s//\1/; p; q
250			}
251			/^.*change-log-time-zone-rule['"$tab"' ]*:['"$tab"' ]*t.*/{
252				s//UTC0/; p; q
253			}
254		'
255		logTZ=`tail "$changelog" | sed -n "$extractTZ"`
256		case $logTZ in
257		?*) TZ=$logTZ; export TZ;;
258		esac
259	fi
260
261	# If CVS is in use, examine its repository, not the normal RCS files.
262	if test ! -f CVS/Repository
263	then
264		rlog=rlog
265		repository=
266	else
267		rlog='cvs -q log'
268		repository=`sed 1q <CVS/Repository` || exit
269		test ! -f CVS/Root || CVSROOT=`cat <CVS/Root` || exit
270		case $CVSROOT in
271		*:/*:/*)
272			echo >&2 "$0: $CVSROOT: CVSROOT has multiple ':/'s"
273			exit 1;;
274		*:/*)
275			# remote repository
276			pository=`expr "X$repository" : '.*:\(/.*\)'`;;
277		*)
278			# local repository
279			case $repository in
280			/*) ;;
281			*) repository=${CVSROOT?}/$repository;;
282			esac
283			if test ! -d "$repository"
284			then
285				echo >&2 "$0: $repository: bad repository (see CVS/Repository)"
286				exit 1
287			fi
288			pository=$repository;;
289		esac
290
291		# Ensure that $pository ends in exactly one slash.
292		while :
293		do
294			case $pository in
295			*//) pository=`expr "X$pository" : 'X\(.*\)/'`;;
296			*/) break;;
297			*) pository=$pository/; break;;
298			esac
299		done
300
301	fi
302
303	# Use $rlog's -zLT option, if $rlog supports it.
304	case `$rlog -zLT 2>&1` in
305	*' option'*) ;;
306	*)
307		case $rlog_options in
308		'') rlog_options=-zLT;;
309		?*) rlog_options=-zLT$nl$rlog_options;;
310		esac;;
311	esac
312
313	# With no arguments, examine all files under the RCS directory.
314	case $# in
315	0)
316		case $repository in
317		'')
318			oldIFS=$IFS
319			IFS=$nl
320			case $recursive in
321			t)
322				RCSdirs=`find . -name RCS -type d -print`
323				filesFromRCSfiles='s|,v$||; s|/RCS/|/|; s|^\./||'
324				files=`
325					{
326						case $RCSdirs in
327						?*) find $RCSdirs \
328								-type f \
329								! -name '*_' \
330								! -name ',*,' \
331								! -name '.*_' \
332								! -name .rcsfreeze.log \
333								! -name .rcsfreeze.ver \
334								-print;;
335						esac
336						find . -name '*,v' -print
337					} |
338					sort -u |
339					sed "$filesFromRCSfiles"
340				`;;
341			*)
342				files=
343				for file in RCS/.* RCS/* .*,v *,v
344				do
345					case $file in
346					RCS/. | RCS/.. | RCS/,*, | RCS/*_) continue;;
347					RCS/.rcsfreeze.log | RCS/.rcsfreeze.ver) continue;;
348					RCS/.\* | RCS/\* | .\*,v | \*,v) test -f "$file" || continue;;
349					RCS/*,v | RCS/.*,v) ;;
350					RCS/* | RCS/.*) test -f "$file" || continue;;
351					esac
352					case $files in
353					'') files=$file;;
354					?*) files=$files$nl$file;;
355					esac
356				done
357				case $files in
358				'') exit 0;;
359				esac;;
360			esac
361			set x $files
362			shift
363			IFS=$oldIFS;;
364		esac;;
365	esac
366
367	case $datearg in
368	?*) $rlog $rlog_options "$datearg" ${1+"$@"} >$rlogfile;;
369	'') $rlog $rlog_options ${1+"$@"} >$rlogfile;;
370	esac || exit;;
371esac
372
373
374# Get the full name of each author the logs mention, and set initialize_fullname
375# to awk code that initializes the `fullname' awk associative array.
376# Warning: foreign authors (i.e. not known in the passwd file) are mishandled;
377# you have to fix the resulting output by hand.
378
379initialize_fullname=
380initialize_mailaddr=
381
382case $loginFullnameMailaddrs in
383?*)
384	case $loginFullnameMailaddrs in
385	*\"* | *\\*)
386		sed 's/["\\]/\\&/g' >$llogout <<EOF || exit
387$loginFullnameMailaddrs
388EOF
389		loginFullnameMailaddrs=`cat $llogout`;;
390	esac
391
392	oldIFS=$IFS
393	IFS=$nl
394	for loginFullnameMailaddr in $loginFullnameMailaddrs
395	do
396		IFS=$tab
397		set x $loginFullnameMailaddr
398		login=$2
399		fullname=$3
400		mailaddr=$4
401		initialize_fullname="$initialize_fullname
402			fullname[\"$login\"] = \"$fullname\""
403		initialize_mailaddr="$initialize_mailaddr
404			mailaddr[\"$login\"] = \"$mailaddr\""
405	done
406	IFS=$oldIFS;;
407esac
408
409case $logins in
410?*)
411	sort -u -o $llogout <<EOF
412$logins
413EOF
414	;;
415'')
416	: ;;
417esac >$llogout || exit
418
419output_authors='/^date: / {
420	if ($2 ~ /^[0-9]*[-\/][0-9][0-9][-\/][0-9][0-9]$/ && $3 ~ /^[0-9][0-9]:[0-9][0-9]:[0-9][0-9][-+0-9:]*;$/ && $4 == "author:" && $5 ~ /^[^;]*;$/) {
421		print substr($5, 1, length($5)-1)
422	}
423}'
424authors=`
425	$AWK "$output_authors" <"$rlogfile" | sort -u | comm -23 - $llogout
426`
427case $authors in
428?*)
429	cat >$llogout <<EOF || exit
430$authors
431EOF
432	initialize_author_script='s/["\\]/\\&/g; s/.*/author[\"&\"] = 1/'
433	initialize_author=`sed -e "$initialize_author_script" <$llogout`
434	awkscript='
435		BEGIN {
436			alphabet = "abcdefghijklmnopqrstuvwxyz"
437			ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
438			'"$initialize_author"'
439		}
440		{
441			if (author[$1]) {
442				fullname = $5
443				if (fullname ~ /[0-9]+-[^(]*\([0-9]+\)$/) {
444					# Remove the junk from fullnames like "0000-Admin(0000)".
445					fullname = substr(fullname, index(fullname, "-") + 1)
446					fullname = substr(fullname, 1, index(fullname, "(") - 1)
447				}
448				if (fullname ~ /,[^ ]/) {
449					# Some sites put comma-separated junk after the fullname.
450					# Remove it, but leave "Bill Gates, Jr" alone.
451					fullname = substr(fullname, 1, index(fullname, ",") - 1)
452				}
453				abbr = index(fullname, "&")
454				if (abbr) {
455					a = substr($1, 1, 1)
456					A = a
457					i = index(alphabet, a)
458					if (i) A = substr(ALPHABET, i, 1)
459					fullname = substr(fullname, 1, abbr-1) A substr($1, 2) substr(fullname, abbr+1)
460				}
461
462				# Quote quotes and backslashes properly in full names.
463				# Do not use gsub; traditional awk lacks it.
464				quoted = ""
465				rest = fullname
466				for (;;) {
467					p = index(rest, "\\")
468					q = index(rest, "\"")
469					if (p) {
470						if (q && q<p) p = q
471					} else {
472						if (!q) break
473						p = q
474					}
475					quoted = quoted substr(rest, 1, p-1) "\\" substr(rest, p, 1)
476					rest = substr(rest, p+1)
477				}
478
479				printf "fullname[\"%s\"] = \"%s%s\"\n", $1, quoted, rest
480				author[$1] = 0
481			}
482		}
483	'
484
485	initialize_fullname=`
486		{
487			(getent passwd $authors) ||
488			(
489				cat /etc/passwd
490				for author in $authors
491				do NIS_PATH= nismatch $author passwd.org_dir
492				done
493				ypmatch $authors passwd
494			)
495		} 2>/dev/null |
496		$AWK -F: "$awkscript"
497	`$initialize_fullname;;
498esac
499
500
501# Function to print a single log line.
502# We don't use awk functions, to stay compatible with old awk versions.
503# `Log' is the log message.
504# `files' contains the affected files.
505printlogline='{
506
507	# Following the GNU coding standards, rewrite
508	#	* file: (function): comment
509	# to
510	#	* file (function): comment
511	if (Log ~ /^\([^)]*\): /) {
512		i = index(Log, ")")
513		filefunc = substr(Log, 1, i)
514		while ((j = index(filefunc, "\n"))) {
515			files = files " " substr(filefunc, 1, j-1)
516			filefunc = substr(filefunc, j+1)
517		}
518		files = files " " filefunc
519		Log = substr(Log, i+3)
520	}
521
522	# If "label: comment" is too long, break the line after the ":".
523	sep = " "
524	i = index(Log, "\n")
525	if ('"$length"' <= '"$indent"' + 1 + length(files) + i) sep = "\n" indent_string
526
527	# Print the label.
528	printf "%s*%s:", indent_string, files
529
530	# Print each line of the log.
531	while (i) {
532		logline = substr(Log, 1, i-1)
533		if (logline ~ /[^'"$tab"' ]/) {
534			printf "%s%s\n", sep, logline
535		} else {
536			print ""
537		}
538		sep = indent_string
539		Log = substr(Log, i+1)
540		i = index(Log, "\n")
541	}
542}'
543
544# Pattern to match the `revision' line of rlog output.
545rlog_revision_pattern='^revision [0-9]+\.[0-9]+(\.[0-9]+\.[0-9]+)*(['"$tab"' ]+locked by: [^'"$tab"' $,.0-9:;@]*[^'"$tab"' $,:;@][^'"$tab"' $,.0-9:;@]*;)?['"$tab"' ]*$'
546
547case $hostname in
548'')
549	hostname=`(
550		hostname || uname -n || uuname -l || cat /etc/whoami
551	) 2>/dev/null` || {
552		echo >&2 "$0: cannot deduce hostname"
553		exit 1
554	}
555
556	case $hostname in
557	*.*) ;;
558	*)
559		domainname=`(domainname) 2>/dev/null` &&
560		case $domainname in
561		*.*) hostname=$hostname.$domainname;;
562		esac;;
563	esac;;
564esac
565
566
567# Process the rlog output, generating ChangeLog style entries.
568
569# First, reformat the rlog output so that each line contains one log entry.
570# Transliterate \n to SOH so that multiline entries fit on a single line.
571# Discard irrelevant rlog output.
572$AWK '
573	BEGIN {
574		pository = "'"$pository"'"
575		SOH="'"$SOH"'"
576	}
577	/^RCS file: / {
578		if (pository != "") {
579			filename = substr($0, 11)
580			if (substr(filename, 1, length(pository)) == pository) {
581				filename = substr(filename, length(pository) + 1)
582			}
583			if (filename ~ /,v$/) {
584				filename = substr(filename, 1, length(filename) - 2)
585			}
586			if (filename ~ /(^|\/)Attic\/[^\/]*$/) {
587				i = length(filename)
588				while (substr(filename, i, 1) != "/") i--
589				filename = substr(filename, 1, i - 6) substr(filename, i + 1)
590			}
591		}
592		rev = "?"
593	}
594	/^Working file: / { if (repository == "") filename = substr($0, 15) }
595	/'"$rlog_revision_pattern"'/, /^(-----------*|===========*)$/ {
596		line = $0
597		if (line ~ /'"$rlog_revision_pattern"'/) {
598			rev = $2
599			next
600		}
601		if (line ~ /^date: [0-9][- +\/0-9:]*;/) {
602			date = $2
603			if (date ~ /\//) {
604				# This is a traditional RCS format date YYYY/MM/DD.
605				# Replace "/"s with "-"s to get ISO format.
606				newdate = ""
607				while ((i = index(date, "/")) != 0) {
608					newdate = newdate substr(date, 1, i-1) "-"
609					date = substr(date, i+1)
610				}
611				date = newdate date
612			}
613			time = substr($3, 1, length($3) - 1)
614			author = substr($5, 1, length($5)-1)
615			printf "%s%s%s%s%s%s%s%s%s%s", filename, SOH, rev, SOH, date, SOH, time, SOH, author, SOH
616			rev = "?"
617			next
618		}
619		if (line ~ /^branches: /) { next }
620		if (line ~ /^(-----------*|===========*)$/) { print ""; next }
621		if (line == "Initial revision" || line ~ /^file .+ was initially added on branch .+\.$/) {
622			line = "New file."
623		}
624		printf "%s%s", line, SOH
625	}
626' <"$rlogfile" |
627
628# Now each line is of the form
629# FILENAME@REVISION@YYYY-MM-DD@HH:MM:SS[+-TIMEZONE]@AUTHOR@LOG
630#	where @ stands for an SOH (octal code 001),
631#	and each line of LOG is terminated by SOH instead of \n.
632# Sort the log entries, first by date+time (in reverse order),
633# then by author, then by log entry, and finally by file name and revision
634# (just in case).
635sort -t"$SOH" +2 -4r +4 +0 |
636
637# Finally, reformat the sorted log entries.
638$AWK -F"$SOH" '
639	BEGIN {
640		logTZ = "'"$logTZ"'"
641		revision = "'"$revision"'"
642
643		# Initialize the fullname and mailaddr associative arrays.
644		'"$initialize_fullname"'
645		'"$initialize_mailaddr"'
646
647		# Initialize indent string.
648		indent_string = ""
649		i = '"$indent"'
650		if (0 < '"$tabwidth"')
651			for (;  '"$tabwidth"' <= i;  i -= '"$tabwidth"')
652				indent_string = indent_string "\t"
653		while (1 <= i--)
654			indent_string = indent_string " "
655	}
656
657	{
658		newlog = ""
659		for (i = 6; i < NF; i++) newlog = newlog $i "\n"
660
661		# Ignore log entries prefixed by "#".
662		if (newlog ~ /^#/) { next }
663
664		if (Log != newlog || date != $3 || author != $5) {
665
666			# The previous log and this log differ.
667
668			# Print the old log.
669			if (date != "") '"$printlogline"'
670
671			# Logs that begin with "{clumpname} " should be grouped together,
672			# and the clumpname should be removed.
673			# Extract the new clumpname from the log header,
674			# and use it to decide whether to output a blank line.
675			newclumpname = ""
676			sep = "\n"
677			if (date == "") sep = ""
678			if (newlog ~ /^\{[^'"$tab"' }]*}['"$tab"' ]/) {
679				i = index(newlog, "}")
680				newclumpname = substr(newlog, 1, i)
681				while (substr(newlog, i+1) ~ /^['"$tab"' ]/) i++
682				newlog = substr(newlog, i+1)
683				if (clumpname == newclumpname) sep = ""
684			}
685			printf sep
686			clumpname = newclumpname
687
688			# Get ready for the next log.
689			Log = newlog
690			if (files != "")
691				for (i in filesknown)
692					filesknown[i] = 0
693			files = ""
694		}
695		if (date != $3  ||  author != $5) {
696			# The previous date+author and this date+author differ.
697			# Print the new one.
698			date = $3
699			time = $4
700			author = $5
701
702			zone = ""
703			if (logTZ && ((i = index(time, "-")) || (i = index(time, "+"))))
704				zone = " " substr(time, i)
705
706			# Print "date[ timezone]  fullname  <email address>".
707			# Get fullname and email address from associative arrays;
708			# default to author and author@hostname if not in arrays.
709			if (fullname[author])
710				auth = fullname[author]
711			else
712				auth = author
713			printf "%s%s  %s  ", date, zone, auth
714			if (mailaddr[author])
715				printf "<%s>\n\n", mailaddr[author]
716			else
717				printf "<%s@%s>\n\n", author, "'"$hostname"'"
718		}
719		if (! filesknown[$1]) {
720			filesknown[$1] = 1
721			if (files == "") files = " " $1
722			else files = files ", " $1
723			if (revision && $2 != "?") files = files " " $2
724		}
725	}
726	END {
727		# Print the last log.
728		if (date != "") {
729			'"$printlogline"'
730			printf "\n"
731		}
732	}
733' &&
734
735
736# Exit successfully.
737
738exec rm -fr $logdir
739
740# Local Variables:
741# tab-width:4
742# End:
743