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