comparison lib-src/rcs2log @ 171:929b76928fce r20-3b12

Import from CVS: tag r20-3b12
author cvs
date Mon, 13 Aug 2007 09:47:52 +0200
parents 376386a54a3c
children
comparison
equal deleted inserted replaced
170:98a42ee61975 171:929b76928fce
1 #!/bin/sh 1 #! /bin/sh
2 2
3 # RCS to ChangeLog generator 3 # RCS to ChangeLog generator
4 4
5 # Generate a change log prefix from RCS files and the ChangeLog (if any). 5 # Generate a change log prefix from RCS files (perhaps in the CVS repository)
6 # and the ChangeLog (if any).
6 # Output the new prefix to standard output. 7 # Output the new prefix to standard output.
7 # You can edit this prefix by hand, and then prepend it to ChangeLog. 8 # You can edit this prefix by hand, and then prepend it to ChangeLog.
8 9
9 # Ignore log entries that start with `#'. 10 # Ignore log entries that start with `#'.
10 # Clump together log entries that start with `{topic} ', 11 # Clump together log entries that start with `{topic} ',
11 # where `topic' contains neither white space nor `}'. 12 # where `topic' contains neither white space nor `}'.
12 13
13 # Author: Paul Eggert <eggert@twinsun.com> 14 Help='The default FILEs are the files registered under the working directory.
14 15 Options:
15 # !Id: rcs2log,v 1.18 1994/08/15 22:44:10 eggert Exp ! 16
16 17 -c CHANGELOG Output a change log prefix to CHANGELOG (default ChangeLog).
17 # Copyright 1992, 1993 Free Software Foundation, Inc. 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).
21 -R If no FILEs are given and RCS is used, recurse through working directory.
22 -r OPTION Pass OPTION to subsidiary log command.
23 -t TABWIDTH Tab stops are every TABWIDTH characters (default 8).
24 -u "LOGIN<tab>FULLNAME<tab>MAILADDR" Assume LOGIN has FULLNAME and MAILADDR.
25 -v Append RCS revision to file names in log lines.
26 --help Output help.
27 --version Output version number.
28
29 Report bugs to <bug-gnu-emacs@prep.ai.mit.edu>.'
30
31 Id='$Id: rcs2log,v 1.2 1997/07/09 04:31:03 steve Exp $'
32
33 # Copyright 1992, 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
18 34
19 # This program is free software; you can redistribute it and/or modify 35 # This program is free software; you can redistribute it and/or modify
20 # it under the terms of the GNU General Public License as published by 36 # it under the terms of the GNU General Public License as published by
21 # the Free Software Foundation; either version 2, or (at your option) 37 # the Free Software Foundation; either version 2, or (at your option)
22 # any later version. 38 # any later version.
23 # 39 #
24 # This program is distributed in the hope that it will be useful, 40 # This program is distributed in the hope that it will be useful,
25 # but WITHOUT ANY WARRANTY; without even the implied warranty of 41 # but WITHOUT ANY WARRANTY; without even the implied warranty of
26 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 42 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 # GNU General Public License for more details. 43 # GNU General Public License for more details.
28 # 44 #
29 # You should have received a copy of the GNU General Public License 45 # You should have received a copy of the GNU General Public License
30 # along with this program; see the file COPYING. If not, write to 46 # along with this program; see the file COPYING. If not, write to the
31 # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 47 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
32 48 # Boston, MA 02111-1307, USA.
49
50 Copyright='Copyright 1997 Free Software Foundation, Inc.
51 This program comes with NO WARRANTY, to the extent permitted by law.
52 You may redistribute copies of this program
53 under the terms of the GNU General Public License.
54 For more information about these matters, see the files named COPYING.
55 Author: Paul Eggert <eggert@twinsun.com>'
56
57 tab=' '
33 nl=' 58 nl='
34 ' 59 '
35 60
36 # Parse options. 61 # Parse options.
37 62
38 # defaults 63 # defaults
64 : ${AWK=awk}
39 : ${TMPDIR=/tmp} 65 : ${TMPDIR=/tmp}
66 changelog=ChangeLog # change log file name
67 datearg= # rlog date option
40 hostname= # name of local host (if empty, will deduce it later) 68 hostname= # name of local host (if empty, will deduce it later)
41 indent=8 # indent of log line 69 indent=8 # indent of log line
42 initialize_fullname= # awk assignments to set up fullname array
43 initialize_mailaddr= # awk assignments to set up mailaddr array
44 length=79 # suggested max width of log line 70 length=79 # suggested max width of log line
45 logins= # login names for people we know fullnames and mailaddresses of 71 logins= # login names for people we know fullnames and mailaddrs of
46 loginsout= # temporary file holding sorted logins 72 loginFullnameMailaddrs= # login<tab>fullname<tab>mailaddr triplets
73 logTZ= # time zone for log dates (if empty, use local time)
74 recursive= # t if we want recursive rlog
75 revision= # t if we want revision numbers
47 rlog_options= # options to pass to rlog 76 rlog_options= # options to pass to rlog
48 tabwidth=8 # width of horizontal tab 77 tabwidth=8 # width of horizontal tab
49 78
50 while : 79 while :
51 do 80 do
52 case $1 in 81 case $1 in
53 -i) indent=${2?};; 82 -c) changelog=${2?}; shift;;
54 -h) hostname=${2?};; 83 -i) indent=${2?}; shift;;
55 -l) length=${2?};; 84 -h) hostname=${2?}; shift;;
56 -n) logins=$logins$nl${2?} 85 -l) length=${2?}; shift;;
57 loginsout=$TMPDIR/rcs2log$$l 86 -[nu]) # -n is obsolescent; it is replaced by -u.
58 case $2${3?}${4?} in 87 case $1 in
59 *\"* | *\\* | *"$nl"*) 88 -n) case ${2?}${3?}${4?} in
60 echo >&2 "$0: -n '$2' '$3' '$4': special characters not allowed" 89 *"$tab"* | *"$nl"*)
61 exit 1 90 echo >&2 "$0: -n '$2' '$3' '$4': tabs, newlines not allowed"
91 exit 1
92 esac
93 loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2$tab$3$tab$4
94 shift; shift; shift;;
95 -u)
96 # If $2 is not tab-separated, use colon for separator.
97 case ${2?} in
98 *"$nl"*)
99 echo >&2 "$0: -u '$2': newlines not allowed"
100 exit 1;;
101 *"$tab"*)
102 t=$tab;;
103 *)
104 t=:
105 esac
106 case $2 in
107 *"$t"*"$t"*"$t"*)
108 echo >&2 "$0: -u '$2': too many fields"
109 exit 1;;
110 *"$t"*"$t"*)
111 ;;
112 *)
113 echo >&2 "$0: -u '$2': not enough fields"
114 exit 1
115 esac
116 loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2
117 shift
62 esac 118 esac
63 initialize_fullname="$initialize_fullname 119 logins=$logins$nl$login
64 fullname[\"$2\"] = \"$3\"" 120 ;;
65 initialize_mailaddr="$initialize_mailaddr 121 -r) rlog_options=$rlog_options$nl${2?}; shift;;
66 mailaddr[\"$2\"] = \"$4\"" 122 -R) recursive=t;;
67 shift; shift;; 123 -t) tabwidth=${2?}; shift;;
68 -r) rlog_options=$rlog_options$nl${2?};; 124 -v) revision=t;;
69 -t) tabwidth=${2?};; 125 --version)
70 -*) echo >&2 "$0: usage: $0 [options] [file ...] 126 set $Id
71 Options: 127 rcs2logVersion=$3
72 [-h hostname] [-i indent] [-l length] [-n login fullname mailaddr]... 128 echo >&2 "rcs2log (GNU Emacs) $rcs2logVersion$nl$Copyright"
73 [-r rlog_option]... [-t tabwidth]" 129 exit 0;;
74 exit 1;; 130 -*) echo >&2 "Usage: $0 [OPTION]... [FILE ...]$nl$Help"
131 case $1 in
132 --help) exit 0;;
133 *) exit 1
134 esac;;
75 *) break 135 *) break
76 esac 136 esac
77 shift; shift 137 shift
78 done 138 done
79 139
80 month_data=' 140 month_data='
81 m[0]="Jan"; m[1]="Feb"; m[2]="Mar" 141 m[0]="Jan"; m[1]="Feb"; m[2]="Mar"
82 m[3]="Apr"; m[4]="May"; m[5]="Jun" 142 m[3]="Apr"; m[4]="May"; m[5]="Jun"
83 m[6]="Jul"; m[7]="Aug"; m[8]="Sep" 143 m[6]="Jul"; m[7]="Aug"; m[8]="Sep"
84 m[9]="Oct"; m[10]="Nov"; m[11]="Dec" 144 m[9]="Oct"; m[10]="Nov"; m[11]="Dec"
85
86 # days in non-leap year thus far, indexed by month (0-12)
87 mo[0]=0; mo[1]=31; mo[2]=59; mo[3]=90
88 mo[4]=120; mo[5]=151; mo[6]=181; mo[7]=212
89 mo[8]=243; mo[9]=273; mo[10]=304; mo[11]=334
90 mo[12]=365
91 ' 145 '
92 146
93 147
94 # Log into $rlogout the revisions checked in since the first ChangeLog entry. 148 # Put rlog output into $rlogout.
95 149
96 date=1970 150 # If no rlog options are given,
97 if test -s ChangeLog 151 # log the revisions checked in since the first ChangeLog entry.
152 # Since ChangeLog is only by date, some of these revisions may be duplicates of
153 # what's already in ChangeLog; it's the user's responsibility to remove them.
154 case $rlog_options in
155 '')
156 if test -s "$changelog"
157 then
158 e='
159 /^[0-9]+-[0-9][0-9]-[0-9][0-9]/{
160 # ISO 8601 date
161 print $1
162 exit
163 }
164 /^... ... [ 0-9][0-9] [ 0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9]+ /{
165 # old-fashioned date and time (Emacs 19.31 and earlier)
166 '"$month_data"'
167 year = $5
168 for (i=0; i<=11; i++) if (m[i] == $2) break
169 dd = $3
170 printf "%d-%02d-%02d\n", year, i+1, dd
171 exit
172 }
173 '
174 d=`$AWK "$e" <"$changelog"` || exit
175 case $d in
176 ?*) datearg="-d>$d"
177 esac
178 fi
179 esac
180
181 # Use TZ specified by ChangeLog local variable, if any.
182 if test -s "$changelog"
98 then 183 then
99 # Add 1 to seconds to avoid duplicating most recent log. 184 extractTZ='
100 e=' 185 /^.*change-log-time-zone-rule['"$tab"' ]*:['"$tab"' ]*"\([^"]*\)".*/{
101 /^... ... [ 0-9][0-9] [ 0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9]+ /{ 186 s//\1/; p; q
102 '"$month_data"' 187 }
103 year = $5 188 /^.*change-log-time-zone-rule['"$tab"' ]*:['"$tab"' ]*t.*/{
104 for (i=0; i<=11; i++) if (m[i] == $2) break 189 s//UTC0/; p; q
105 dd = $3
106 hh = substr($0,12,2)
107 mm = substr($0,15,2)
108 ss = substr($0,18,2)
109 ss++
110 if (ss == 60) {
111 ss = 0
112 mm++
113 if (mm == 60) {
114 mm = 0
115 hh++
116 if (hh == 24) {
117 hh = 0
118 dd++
119 monthdays = mo[i+1] - mo[i]
120 if (i == 1 && year%4 == 0 && (year%100 != 0 || year%400 == 0)) monthdays++
121 if (dd == monthdays + 1) {
122 dd = 1
123 i++
124 if (i == 12) {
125 i = 0
126 year++
127 }
128 }
129 }
130 }
131 }
132 printf "%d/%02d/%02d %02d:%02d:%02d\n", year, i+1, dd, hh, mm, ss
133 exit
134 } 190 }
135 ' 191 '
136 d=`awk "$e" <ChangeLog` || exit 192 logTZ=`tail "$changelog" | sed -n "$extractTZ"`
137 case $d in 193 case $logTZ in
138 ?*) date=$d 194 ?*) TZ=$logTZ; export TZ
139 esac 195 esac
140 fi 196 fi
141 datearg="-d>$date" 197
142 198 # If CVS is in use, examine its repository, not the normal RCS files.
143 repository= 199 if test ! -f CVS/Repository
144 rlog=rlog 200 then
145 case $CVSROOT in 201 rlog=rlog
146 ?*) 202 repository=
147 if test -d "$CVSROOT" && test -f CVS/Repository 203 else
148 then 204 rlog='cvs -q log'
149 r=`cat <CVS/Repository` || exit 205 repository=`sed 1q <CVS/Repository` || exit
150 if test -d "$CVSROOT/$r" 206 test ! -f CVS/Root || CVSROOT=`cat <CVS/Root` || exit
207 case $CVSROOT in
208 *:/*)
209 # remote repository
210 ;;
211 *)
212 # local repository
213 case $repository in
214 /*) ;;
215 *) repository=${CVSROOT?}/$repository
216 esac
217 if test ! -d "$repository"
151 then 218 then
152 repository=$CVSROOT/$r 219 echo >&2 "$0: $repository: bad repository (see CVS/Repository)"
153 rlog='cvs log' 220 exit 1
154 fi 221 fi
155 fi 222 esac
223 fi
224
225 # Use $rlog's -zLT option, if $rlog supports it.
226 case `$rlog -zLT 2>&1` in
227 *' option'*) ;;
228 *) rlog_options=-zLT$nl$rlog_options
156 esac 229 esac
157 230
158 # With no arguments, examine all files under the RCS directory. 231 # With no arguments, examine all files under the RCS directory.
159 case $# in 232 case $# in
160 0) 233 0)
161 case $repository in 234 case $repository in
162 '') 235 '')
163 files=
164 for file in RCS/.* RCS/* .*,v *,v
165 do
166 case $file in
167 RCS/. | RCS/..) continue;;
168 RCS/.\* | RCS/\* | .\*,v | \*,v) test -f "$file" || continue
169 esac
170 files=$files$nl$file
171 done
172 case $files in
173 '') exit 0
174 esac
175 oldIFS=$IFS 236 oldIFS=$IFS
176 IFS=$nl 237 IFS=$nl
177 set $files 238 case $recursive in
239 t)
240 RCSdirs=`find . -name RCS -type d -print`
241 filesFromRCSfiles='s|,v$||; s|/RCS/|/|; s|^\./||'
242 files=`
243 {
244 case $RCSdirs in
245 ?*) find $RCSdirs \
246 -type f \
247 ! -name '*_' \
248 ! -name ',*,' \
249 ! -name '.*_' \
250 ! -name .rcsfreeze.log \
251 ! -name .rcsfreeze.ver \
252 -print
253 esac
254 find . -name '*,v' -print
255 } |
256 sort -u |
257 sed "$filesFromRCSfiles"
258 `;;
259 *)
260 files=
261 for file in RCS/.* RCS/* .*,v *,v
262 do
263 case $file in
264 RCS/. | RCS/.. | RCS/,*, | RCS/*_) continue;;
265 RCS/.rcsfreeze.log | RCS/.rcsfreeze.ver) continue;;
266 RCS/.\* | RCS/\* | .\*,v | \*,v) test -f "$file" || continue
267 esac
268 files=$files$nl$file
269 done
270 case $files in
271 '') exit 0
272 esac
273 esac
274 set x $files
275 shift
178 IFS=$oldIFS 276 IFS=$oldIFS
179 esac 277 esac
180 esac 278 esac
181 279
280 llogout=$TMPDIR/rcs2log$$l
182 rlogout=$TMPDIR/rcs2log$$r 281 rlogout=$TMPDIR/rcs2log$$r
183 trap exit 1 2 13 15 282 trap exit 1 2 13 15
184 trap "rm -f $loginsout $rlogout; exit 1" 0 283 trap "rm -f $llogout $rlogout; exit 1" 0
185 284
186 $rlog "$datearg" $rlog_options ${1+"$@"} >$rlogout || exit 285 case $datearg in
286 ?*) $rlog $rlog_options "$datearg" ${1+"$@"} >$rlogout;;
287 '') $rlog $rlog_options ${1+"$@"} >$rlogout
288 esac || exit
187 289
188 290
189 # Get the full name of each author the logs mention, and set initialize_fullname 291 # Get the full name of each author the logs mention, and set initialize_fullname
190 # to awk code that initializes the `fullname' awk associative array. 292 # to awk code that initializes the `fullname' awk associative array.
191 # Warning: foreign authors (i.e. not known in the passwd file) are mishandled; 293 # Warning: foreign authors (i.e. not known in the passwd file) are mishandled;
192 # you have to fix the resulting output by hand. 294 # you have to fix the resulting output by hand.
193 295
194 case $loginsout in 296 initialize_fullname=
195 ?*) sort -u -o $loginsout <<EOF || exit 297 initialize_mailaddr=
298
299 case $loginFullnameMailaddrs in
300 ?*)
301 case $loginFullnameMailaddrs in
302 *\"* | *\\*)
303 sed 's/["\\]/\\&/g' >$llogout <<EOF || exit
304 $loginFullnameMailaddrs
305 EOF
306 loginFullnameMailaddrs=`cat $llogout`
307 esac
308
309 oldIFS=$IFS
310 IFS=$nl
311 for loginFullnameMailaddr in $loginFullnameMailaddrs
312 do
313 case $loginFullnameMailaddr in
314 *"$tab"*) IFS=$tab;;
315 *) IFS=:
316 esac
317 set x $loginFullnameMailaddr
318 login=$2
319 fullname=$3
320 mailaddr=$4
321 initialize_fullname="$initialize_fullname
322 fullname[\"$login\"] = \"$fullname\""
323 initialize_mailaddr="$initialize_mailaddr
324 mailaddr[\"$login\"] = \"$mailaddr\""
325 done
326 IFS=$oldIFS
327 esac
328
329 case $llogout in
330 ?*) sort -u -o $llogout <<EOF || exit
196 $logins 331 $logins
197 EOF 332 EOF
198 esac 333 esac
334 output_authors='/^date: / {
335 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 ~ /^[^;]*;$/) {
336 print substr($5, 1, length($5)-1)
337 }
338 }'
199 authors=` 339 authors=`
200 sed -n 's|^date: *[0-9]*[-/][0-9][0-9][-/][0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9][-+0-9]*; *author: *\([^; ]*\).*|\1|p' <$rlogout | 340 $AWK "$output_authors" <$rlogout |
201 case $loginsout in 341 case $llogout in
202 '') sort -u;; 342 '') sort -u;;
203 ?*) sort -u | comm -23 - $loginsout 343 ?*) sort -u | comm -23 - $llogout
204 esac 344 esac
205 ` 345 `
206 case $authors in 346 case $authors in
207 ?*) 347 ?*)
208 initialize_author= 348 cat >$llogout <<EOF || exit
209 for author in $authors 349 $authors
210 do 350 EOF
211 initialize_author="$initialize_author 351 initialize_author_script='s/["\\]/\\&/g; s/.*/author[\"&\"] = 1/'
212 author[\"$author\"] = 1 352 initialize_author=`sed -e "$initialize_author_script" <$llogout`
213 "
214 done
215 awkscript=' 353 awkscript='
216 BEGIN { 354 BEGIN {
217 alphabet = "abcdefghijklmnopqrstuvwxyz" 355 alphabet = "abcdefghijklmnopqrstuvwxyz"
218 ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 356 ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
219 '"$initialize_author"' 357 '"$initialize_author"'
237 A = a 375 A = a
238 i = index(alphabet, a) 376 i = index(alphabet, a)
239 if (i) A = substr(ALPHABET, i, 1) 377 if (i) A = substr(ALPHABET, i, 1)
240 fullname = substr(fullname, 1, abbr-1) A substr($1, 2) substr(fullname, abbr+1) 378 fullname = substr(fullname, 1, abbr-1) A substr($1, 2) substr(fullname, abbr+1)
241 } 379 }
242 printf "fullname[\"%s\"] = \"%s\"\n", $1, fullname 380
381 # Quote quotes and backslashes properly in full names.
382 # Do not use gsub; traditional awk lacks it.
383 quoted = ""
384 rest = fullname
385 for (;;) {
386 p = index(rest, "\\")
387 q = index(rest, "\"")
388 if (p) {
389 if (q && q<p) p = q
390 } else {
391 if (!q) break
392 p = q
393 }
394 quoted = quoted substr(rest, 1, p-1) "\\" substr(rest, p, 1)
395 rest = substr(rest, p+1)
396 }
397
398 printf "fullname[\"%s\"] = \"%s%s\"\n", $1, quoted, rest
243 author[$1] = 0 399 author[$1] = 0
244 } 400 }
245 } 401 }
246 ' 402 '
247 403
248 initialize_fullname=` 404 initialize_fullname=`
249 (cat /etc/passwd; ypmatch $authors passwd) 2>/dev/null | 405 (
250 awk -F: "$awkscript" 406 cat /etc/passwd
407 for author in $authors
408 do nismatch $author passwd.org_dir
409 done
410 ypmatch $authors passwd
411 ) 2>/dev/null |
412 $AWK -F: "$awkscript"
251 `$initialize_fullname 413 `$initialize_fullname
252 esac 414 esac
253 415
254 416
255 # Function to print a single log line. 417 # Function to print a single log line.
276 printf "%s*%s:", indent_string, files 438 printf "%s*%s:", indent_string, files
277 439
278 # Print each line of the log, transliterating \r to \n. 440 # Print each line of the log, transliterating \r to \n.
279 while ((i = index(Log, CR)) != 0) { 441 while ((i = index(Log, CR)) != 0) {
280 logline = substr(Log, 1, i-1) 442 logline = substr(Log, 1, i-1)
281 if (logline ~ /[^ ]/) { 443 if (logline ~ /[^'"$tab"' ]/) {
282 printf "%s%s\n", sep, logline 444 printf "%s%s\n", sep, logline
283 } else { 445 } else {
284 print "" 446 print ""
285 } 447 }
286 sep = indent_string 448 sep = indent_string
287 Log = substr(Log, i+1) 449 Log = substr(Log, i+1)
288 } 450 }
289 }' 451 }'
452
453 # Pattern to match the `revision' line of rlog output.
454 rlog_revision_pattern='^revision [0-9]+\.[0-9]+(\.[0-9]+\.[0-9]+)*(['"$tab"' ]+locked by: [^'"$tab"' $,.0-9:;@]*[^'"$tab"' $,:;@][^'"$tab"' $,.0-9:;@]*;)?['"$tab"' ]*$'
290 455
291 case $hostname in 456 case $hostname in
292 '') 457 '')
293 hostname=`( 458 hostname=`(
294 hostname || uname -n || uuname -l || cat /etc/whoami 459 hostname || uname -n || uuname -l || cat /etc/whoami
295 ) 2>/dev/null` || { 460 ) 2>/dev/null` || {
296 echo >&2 "$0: cannot deduce hostname" 461 echo >&2 "$0: cannot deduce hostname"
297 exit 1 462 exit 1
298 } 463 }
464
465 case $hostname in
466 *.*) ;;
467 *)
468 domainname=`(domainname) 2>/dev/null` &&
469 case $domainname in
470 *.*) hostname=$hostname.$domainname
471 esac
472 esac
299 esac 473 esac
300 474
301 475
302 # Process the rlog output, generating ChangeLog style entries. 476 # Process the rlog output, generating ChangeLog style entries.
303 477
304 # First, reformat the rlog output so that each line contains one log entry. 478 # First, reformat the rlog output so that each line contains one log entry.
305 # Transliterate \n to \r so that multiline entries fit on a single line. 479 # Transliterate \n to \r so that multiline entries fit on a single line.
306 # Discard irrelevant rlog output. 480 # Discard irrelevant rlog output.
307 awk <$rlogout ' 481 $AWK <$rlogout '
308 /^Working file:/ { filename = $3 } 482 BEGIN { repository = "'"$repository"'" }
309 /^date: /, /^(-----------*|===========*)$/ { 483 /^RCS file:/ {
310 if ($0 ~ /^branches: /) { next } 484 if (repository != "") {
485 filename = $3
486 if (substr(filename, 1, length(repository) + 1) == repository "/") {
487 filename = substr(filename, length(repository) + 2)
488 }
489 if (filename ~ /,v$/) {
490 filename = substr(filename, 1, length(filename) - 2)
491 }
492 if (filename ~ /(^|\/)Attic\/[^\/]*$/) {
493 i = length(filename)
494 while (substr(filename, i, 1) != "/") i--
495 filename = substr(filename, 1, i - 6) substr(filename, i + 1)
496 }
497 }
498 rev = "?"
499 }
500 /^Working file:/ { if (repository == "") filename = $3 }
501 /'"$rlog_revision_pattern"'/, /^(-----------*|===========*)$/ {
502 if ($0 ~ /'"$rlog_revision_pattern"'/) {
503 rev = $2
504 next
505 }
311 if ($0 ~ /^date: [0-9][- +\/0-9:]*;/) { 506 if ($0 ~ /^date: [0-9][- +\/0-9:]*;/) {
312 date = $2 507 date = $2
313 if (date ~ /-/) { 508 if (date ~ /\//) {
314 # An ISO format date. Replace all "-"s with "/"s. 509 # This is a traditional RCS format date YYYY/MM/DD.
510 # Replace "/"s with "-"s to get ISO format.
315 newdate = "" 511 newdate = ""
316 while ((i = index(date, "-")) != 0) { 512 while ((i = index(date, "/")) != 0) {
317 newdate = newdate substr(date, 1, i-1) "/" 513 newdate = newdate substr(date, 1, i-1) "-"
318 date = substr(date, i+1) 514 date = substr(date, i+1)
319 } 515 }
320 date = newdate date 516 date = newdate date
321 } 517 }
322 # Ignore any time zone; ChangeLog has no room for it. 518 time = substr($3, 1, length($3) - 1)
323 time = substr($3, 1, 8)
324 author = substr($5, 1, length($5)-1) 519 author = substr($5, 1, length($5)-1)
325 printf "%s %s %s %s %c", filename, date, time, author, 13 520 printf "%s %s %s %s %s %c", filename, rev, date, time, author, 13
521 rev = "?"
326 next 522 next
327 } 523 }
524 if ($0 ~ /^branches: /) { next }
328 if ($0 ~ /^(-----------*|===========*)$/) { print ""; next } 525 if ($0 ~ /^(-----------*|===========*)$/) { print ""; next }
526 if ($0 == "Initial revision" || $0 ~ /^file .+ was initially added on branch .+\.$/) {
527 $0 = "New file."
528 }
329 printf "%s%c", $0, 13 529 printf "%s%c", $0, 13
330 } 530 }
331 ' | 531 ' |
332 532
333 # Now each line is of the form 533 # Now each line is of the form
334 # FILENAME YYYY/MM/DD HH:MM:SS AUTHOR \rLOG 534 # FILENAME REVISION YYYY-MM-DD HH:MM:SS[+-TIMEZONE] AUTHOR \rLOG
335 # where \r stands for a carriage return, 535 # where \r stands for a carriage return,
336 # and each line of the log is terminated by \r instead of \n. 536 # and each line of the log is terminated by \r instead of \n.
337 # Sort the log entries, first by date+time (in reverse order), 537 # Sort the log entries, first by date+time (in reverse order),
338 # then by author, then by log entry, and finally by file name (just in case). 538 # then by author, then by log entry, and finally by file name and revision
339 sort +1 -3r +3 +0 | 539 # (just in case).
540 sort +2 -4r +4 +0 |
340 541
341 # Finally, reformat the sorted log entries. 542 # Finally, reformat the sorted log entries.
342 awk ' 543 $AWK '
343 BEGIN { 544 BEGIN {
344 # Some awks do not understand "\r" or "\013", so we have to 545 logTZ = "'"$logTZ"'"
546 revision = "'"$revision"'"
547
548 # Some awk variants do not understand "\r" or "\013", so we have to
345 # put a carriage return directly in the file. 549 # put a carriage return directly in the file.
346 CR=" 550 CR="
347 " # <-- There is a single CR between the " chars here. 551 " # <-- There is a single CR between the " chars here.
348 552
349 # Initialize the fullname and mailaddr associative arrays. 553 # Initialize the fullname and mailaddr associative arrays.
356 if (0 < '"$tabwidth"') 560 if (0 < '"$tabwidth"')
357 for (; '"$tabwidth"' <= i; i -= '"$tabwidth"') 561 for (; '"$tabwidth"' <= i; i -= '"$tabwidth"')
358 indent_string = indent_string "\t" 562 indent_string = indent_string "\t"
359 while (1 <= i--) 563 while (1 <= i--)
360 indent_string = indent_string " " 564 indent_string = indent_string " "
361
362 # Set up date conversion tables.
363 # RCS uses a nice, clean, sortable format,
364 # but ChangeLog wants the traditional, ugly ctime format.
365
366 # January 1, 0 AD (Gregorian) was Saturday = 6
367 EPOCH_WEEKDAY = 6
368 # Of course, there was no 0 AD, but the algorithm works anyway.
369
370 w[0]="Sun"; w[1]="Mon"; w[2]="Tue"; w[3]="Wed"
371 w[4]="Thu"; w[5]="Fri"; w[6]="Sat"
372
373 '"$month_data"'
374 } 565 }
375 566
376 { 567 {
377 newlog = substr($0, 1 + index($0, CR)) 568 newlog = substr($0, 1 + index($0, CR))
378 569
379 # Ignore log entries prefixed by "#". 570 # Ignore log entries prefixed by "#".
380 if (newlog ~ /^#/) { next } 571 if (newlog ~ /^#/) { next }
381 572
382 if (Log != newlog || date != $2 || author != $4) { 573 if (Log != newlog || date != $3 || author != $5) {
383 574
384 # The previous log and this log differ. 575 # The previous log and this log differ.
385 576
386 # Print the old log. 577 # Print the old log.
387 if (date != "") '"$printlogline"' 578 if (date != "") '"$printlogline"'
391 # Extract the new clumpname from the log header, 582 # Extract the new clumpname from the log header,
392 # and use it to decide whether to output a blank line. 583 # and use it to decide whether to output a blank line.
393 newclumpname = "" 584 newclumpname = ""
394 sep = "\n" 585 sep = "\n"
395 if (date == "") sep = "" 586 if (date == "") sep = ""
396 if (newlog ~ /^\{[^ }]*}[ ]/) { 587 if (newlog ~ /^\{[^'"$tab"' }]*}['"$tab"' ]/) {
397 i = index(newlog, "}") 588 i = index(newlog, "}")
398 newclumpname = substr(newlog, 1, i) 589 newclumpname = substr(newlog, 1, i)
399 while (substr(newlog, i+1) ~ /^[ ]/) i++ 590 while (substr(newlog, i+1) ~ /^['"$tab"' ]/) i++
400 newlog = substr(newlog, i+1) 591 newlog = substr(newlog, i+1)
401 if (clumpname == newclumpname) sep = "" 592 if (clumpname == newclumpname) sep = ""
402 } 593 }
403 printf sep 594 printf sep
404 clumpname = newclumpname 595 clumpname = newclumpname
408 if (files != "") 599 if (files != "")
409 for (i in filesknown) 600 for (i in filesknown)
410 filesknown[i] = 0 601 filesknown[i] = 0
411 files = "" 602 files = ""
412 } 603 }
413 if (date != $2 || author != $4) { 604 if (date != $3 || author != $5) {
414 # The previous date+author and this date+author differ. 605 # The previous date+author and this date+author differ.
415 # Print the new one. 606 # Print the new one.
416 date = $2 607 date = $3
417 author = $4 608 time = $4
418 609 author = $5
419 # Convert nice RCS date like "1992/01/03 00:03:44" 610
420 # into ugly ctime date like "Fri Jan 3 00:03:44 1992". 611 zone = ""
421 # Calculate day of week from Gregorian calendar. 612 if (logTZ && ((i = index(time, "-")) || (i = index(time, "+"))))
422 i = index($2, "/") 613 zone = " " substr(time, i)
423 year = substr($2, 1, i-1) + 0 614
424 monthday = substr($2, i+1) 615 # Print "date[ timezone] fullname <email address>".
425 i = index(monthday, "/")
426 month = substr(monthday, 1, i-1) + 0
427 day = substr(monthday, i+1) + 0
428 leap = 0
429 if (2 < month && year%4 == 0 && (year%100 != 0 || year%400 == 0)) leap = 1
430 days_since_Sunday_before_epoch = EPOCH_WEEKDAY + year * 365 + int((year + 3) / 4) - int((year + 99) / 100) + int((year + 399) / 400) + mo[month-1] + leap + day - 1
431
432 # Print "date fullname (email address)".
433 # Get fullname and email address from associative arrays; 616 # Get fullname and email address from associative arrays;
434 # default to author and author@hostname if not in arrays. 617 # default to author and author@hostname if not in arrays.
435 if (fullname[author]) 618 if (fullname[author])
436 auth = fullname[author] 619 auth = fullname[author]
437 else 620 else
438 auth = author 621 auth = author
439 printf "%s %s %2d %s %d %s ", w[days_since_Sunday_before_epoch%7], m[month-1], day, $3, year, auth 622 printf "%s%s %s ", date, zone, auth
440 if (mailaddr[author]) 623 if (mailaddr[author])
441 printf "<%s>\n\n", mailaddr[author] 624 printf "<%s>\n\n", mailaddr[author]
442 else 625 else
443 printf "<%s@%s>\n\n", author, "'"$hostname"'" 626 printf "<%s@%s>\n\n", author, "'"$hostname"'"
444 } 627 }
445 if (! filesknown[$1]) { 628 if (! filesknown[$1]) {
446 filesknown[$1] = 1 629 filesknown[$1] = 1
447 if (files == "") files = " " $1 630 if (files == "") files = " " $1
448 else files = files ", " $1 631 else files = files ", " $1
632 if (revision && $2 != "?") files = files " " $2
449 } 633 }
450 } 634 }
451 END { 635 END {
452 # Print the last log. 636 # Print the last log.
453 if (date != "") { 637 if (date != "") {
458 ' && 642 ' &&
459 643
460 644
461 # Exit successfully. 645 # Exit successfully.
462 646
463 exec rm -f $loginsout $rlogout 647 exec rm -f $llogout $rlogout
648
649 # Local Variables:
650 # tab-width:4
651 # End: