PageRenderTime 3157ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/src/freebsd/contrib/cvs/contrib/rcs2log.sh

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