comparison lib-src/rcs2log @ 1238:97cb5bab4ea0

[xemacs-hg @ 2003-01-28 03:19:04 by youngs] 2003-01-28 Steve Youngs <youngs@xemacs.org> * rcs2log: Synch to GNU version.
author youngs
date Tue, 28 Jan 2003 03:19:04 +0000
parents 3ecd8885ac67
children 061f4f90f874
comparison
equal deleted inserted replaced
1237:0944ae906674 1238:97cb5bab4ea0
16 16
17 -c CHANGELOG Output a change log prefix to CHANGELOG (default ChangeLog). 17 -c CHANGELOG Output a change log prefix to CHANGELOG (default ChangeLog).
18 -h HOSTNAME Use HOSTNAME in change log entries (default current host). 18 -h HOSTNAME Use HOSTNAME in change log entries (default current host).
19 -i INDENT Indent change log lines by INDENT spaces (default 8). 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). 20 -l LENGTH Try to limit log lines to LENGTH characters (default 79).
21 -L FILE Use rlog-format FILE for source of logs.
21 -R If no FILEs are given and RCS is used, recurse through working directory. 22 -R If no FILEs are given and RCS is used, recurse through working directory.
22 -r OPTION Pass OPTION to subsidiary log command. 23 -r OPTION Pass OPTION to subsidiary log command.
23 -t TABWIDTH Tab stops are every TABWIDTH characters (default 8). 24 -t TABWIDTH Tab stops are every TABWIDTH characters (default 8).
24 -u "LOGIN<tab>FULLNAME<tab>MAILADDR" Assume LOGIN has FULLNAME and MAILADDR. 25 -u "LOGIN<tab>FULLNAME<tab>MAILADDR" Assume LOGIN has FULLNAME and MAILADDR.
25 -v Append RCS revision to file names in log lines. 26 -v Append RCS revision to file names in log lines.
26 --help Output help. 27 --help Output help.
27 --version Output version number. 28 --version Output version number.
28 29
29 Report bugs to <bug-gnu-emacs@prep.ai.mit.edu>.' 30 Report bugs to <bug-gnu-emacs@gnu.org>.'
30 31
31 Id='$Id: rcs2log,v 1.2 1997/07/09 04:31:03 steve Exp $' 32 Id='$Id: rcs2log,v 1.3 2003/01/28 03:19:04 youngs Exp $'
32 33
33 # Copyright 1992, 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc. 34 # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2001, 2002
35 # Free Software Foundation, Inc.
34 36
35 # This program is free software; you can redistribute it and/or modify 37 # This program is free software; you can redistribute it and/or modify
36 # it under the terms of the GNU General Public License as published by 38 # it under the terms of the GNU General Public License as published by
37 # the Free Software Foundation; either version 2, or (at your option) 39 # the Free Software Foundation; either version 2, or (at your option)
38 # any later version. 40 # any later version.
45 # You should have received a copy of the GNU General Public License 47 # You should have received a copy of the GNU General Public License
46 # along with this program; see the file COPYING. If not, write to the 48 # along with this program; see the file COPYING. If not, write to the
47 # Free Software Foundation, Inc., 59 Temple Place - Suite 330, 49 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
48 # Boston, MA 02111-1307, USA. 50 # Boston, MA 02111-1307, USA.
49 51
50 Copyright='Copyright 1997 Free Software Foundation, Inc. 52 Copyright='Copyright (C) 2002 Free Software Foundation, Inc.
51 This program comes with NO WARRANTY, to the extent permitted by law. 53 This program comes with NO WARRANTY, to the extent permitted by law.
52 You may redistribute copies of this program 54 You may redistribute copies of this program
53 under the terms of the GNU General Public License. 55 under the terms of the GNU General Public License.
54 For more information about these matters, see the files named COPYING. 56 For more information about these matters, see the files named COPYING.
55 Author: Paul Eggert <eggert@twinsun.com>' 57 Author: Paul Eggert <eggert@twinsun.com>'
56 58
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
57 tab=' ' 75 tab=' '
58 nl=' 76 nl='
59 ' 77 '
60 78
61 # Parse options. 79 # Parse options.
62 80
63 # defaults 81 # defaults
64 : ${AWK=awk} 82 AWK=${AWK-awk}
65 : ${TMPDIR=/tmp} 83 TMPDIR=${TMPDIR-/tmp}
66 changelog=ChangeLog # change log file name 84 changelog=ChangeLog # change log file name
67 datearg= # rlog date option 85 datearg= # rlog date option
68 hostname= # name of local host (if empty, will deduce it later) 86 hostname= # name of local host (if empty, will deduce it later)
69 indent=8 # indent of log line 87 indent=8 # indent of log line
70 length=79 # suggested max width of log line 88 length=79 # suggested max width of log line
72 loginFullnameMailaddrs= # login<tab>fullname<tab>mailaddr triplets 90 loginFullnameMailaddrs= # login<tab>fullname<tab>mailaddr triplets
73 logTZ= # time zone for log dates (if empty, use local time) 91 logTZ= # time zone for log dates (if empty, use local time)
74 recursive= # t if we want recursive rlog 92 recursive= # t if we want recursive rlog
75 revision= # t if we want revision numbers 93 revision= # t if we want revision numbers
76 rlog_options= # options to pass to rlog 94 rlog_options= # options to pass to rlog
95 rlogfile= # log file to read from
77 tabwidth=8 # width of horizontal tab 96 tabwidth=8 # width of horizontal tab
78 97
79 while : 98 while :
80 do 99 do
81 case $1 in 100 case $1 in
82 -c) changelog=${2?}; shift;; 101 -c) changelog=${2?}; shift;;
83 -i) indent=${2?}; shift;; 102 -i) indent=${2?}; shift;;
84 -h) hostname=${2?}; shift;; 103 -h) hostname=${2?}; shift;;
85 -l) length=${2?}; shift;; 104 -l) length=${2?}; shift;;
105 -L) rlogfile=${2?}; shift;;
86 -[nu]) # -n is obsolescent; it is replaced by -u. 106 -[nu]) # -n is obsolescent; it is replaced by -u.
87 case $1 in 107 case $1 in
88 -n) case ${2?}${3?}${4?} in 108 -n) case ${2?}${3?}${4?} in
89 *"$tab"* | *"$nl"*) 109 *"$tab"* | *"$nl"*)
90 echo >&2 "$0: -n '$2' '$3' '$4': tabs, newlines not allowed" 110 echo >&2 "$0: -n '$2' '$3' '$4': tabs, newlines not allowed"
91 exit 1 111 exit 1;;
92 esac 112 esac
93 loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2$tab$3$tab$4 113 login=$2
114 lfm=$2$tab$3$tab$4
94 shift; shift; shift;; 115 shift; shift; shift;;
95 -u) 116 -u)
96 # If $2 is not tab-separated, use colon for separator. 117 # If $2 is not tab-separated, use colon for separator.
97 case ${2?} in 118 case ${2?} in
98 *"$nl"*) 119 *"$nl"*)
99 echo >&2 "$0: -u '$2': newlines not allowed" 120 echo >&2 "$0: -u '$2': newlines not allowed"
100 exit 1;; 121 exit 1;;
101 *"$tab"*) 122 *"$tab"*)
102 t=$tab;; 123 t=$tab;;
103 *) 124 *)
104 t=: 125 t=':';;
105 esac 126 esac
106 case $2 in 127 case $2 in
107 *"$t"*"$t"*"$t"*) 128 *"$t"*"$t"*"$t"*)
108 echo >&2 "$0: -u '$2': too many fields" 129 echo >&2 "$0: -u '$2': too many fields"
109 exit 1;; 130 exit 1;;
110 *"$t"*"$t"*) 131 *"$t"*"$t"*)
111 ;; 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 `;;
112 *) 140 *)
113 echo >&2 "$0: -u '$2': not enough fields" 141 echo >&2 "$0: -u '$2': not enough fields"
114 exit 1 142 exit 1;;
115 esac 143 esac
116 loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2 144 shift;;
117 shift
118 esac 145 esac
119 logins=$logins$nl$login 146 case $logins in
120 ;; 147 '') logins=$login;;
121 -r) rlog_options=$rlog_options$nl${2?}; shift;; 148 ?*) logins=$logins$nl$login;;
149 esac
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;;
122 -R) recursive=t;; 160 -R) recursive=t;;
123 -t) tabwidth=${2?}; shift;; 161 -t) tabwidth=${2?}; shift;;
124 -v) revision=t;; 162 -v) revision=t;;
125 --version) 163 --version)
126 set $Id 164 set $Id
128 echo >&2 "rcs2log (GNU Emacs) $rcs2logVersion$nl$Copyright" 166 echo >&2 "rcs2log (GNU Emacs) $rcs2logVersion$nl$Copyright"
129 exit 0;; 167 exit 0;;
130 -*) echo >&2 "Usage: $0 [OPTION]... [FILE ...]$nl$Help" 168 -*) echo >&2 "Usage: $0 [OPTION]... [FILE ...]$nl$Help"
131 case $1 in 169 case $1 in
132 --help) exit 0;; 170 --help) exit 0;;
133 *) exit 1 171 *) exit 1;;
134 esac;; 172 esac;;
135 *) break 173 *) break;;
136 esac 174 esac
137 shift 175 shift
138 done 176 done
139 177
140 month_data=' 178 month_data='
142 m[3]="Apr"; m[4]="May"; m[5]="Jun" 180 m[3]="Apr"; m[4]="May"; m[5]="Jun"
143 m[6]="Jul"; m[7]="Aug"; m[8]="Sep" 181 m[6]="Jul"; m[7]="Aug"; m[8]="Sep"
144 m[9]="Oct"; m[10]="Nov"; m[11]="Dec" 182 m[9]="Oct"; m[10]="Nov"; m[11]="Dec"
145 ' 183 '
146 184
147 185 logdir=$TMPDIR/rcs2log$$
148 # Put rlog output into $rlogout. 186 llogout=$logdir/l
149 187 trap exit 1 2 13 15
150 # If no rlog options are given, 188 trap "rm -fr $logdir 2>/dev/null" 0
151 # log the revisions checked in since the first ChangeLog entry. 189 (umask 077 && exec mkdir $logdir) || exit
152 # Since ChangeLog is only by date, some of these revisions may be duplicates of 190
153 # what's already in ChangeLog; it's the user's responsibility to remove them. 191 # If no rlog-format log file is given, generate one into $rlogfile.
154 case $rlog_options in 192 case $rlogfile in
155 '') 193 '')
194 rlogfile=$logdir/r
195
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.
156 if test -s "$changelog" 228 if test -s "$changelog"
157 then 229 then
158 e=' 230 extractTZ='
159 /^[0-9]+-[0-9][0-9]-[0-9][0-9]/{ 231 /^.*change-log-time-zone-rule['"$tab"' ]*:['"$tab"' ]*"\([^"]*\)".*/{
160 # ISO 8601 date 232 s//\1/; p; q
161 print $1
162 exit
163 } 233 }
164 /^... ... [ 0-9][0-9] [ 0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9]+ /{ 234 /^.*change-log-time-zone-rule['"$tab"' ]*:['"$tab"' ]*t.*/{
165 # old-fashioned date and time (Emacs 19.31 and earlier) 235 s//UTC0/; p; q
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 } 236 }
173 ' 237 '
174 d=`$AWK "$e" <"$changelog"` || exit 238 logTZ=`tail "$changelog" | sed -n "$extractTZ"`
175 case $d in 239 case $logTZ in
176 ?*) datearg="-d>$d" 240 ?*) TZ=$logTZ; export TZ;;
177 esac 241 esac
178 fi 242 fi
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;;
179 esac 354 esac
180 355
181 # Use TZ specified by ChangeLog local variable, if any. 356
182 if test -s "$changelog" 357 # Prefer the POSIX-style -k options, since POSIX 1003.1-2001 prohibits
183 then 358 # support for the traditional-style +M -N options.
184 extractTZ=' 359 SORT_K_OPTIONS='-k 3,4r -k 5 -k 1'
185 /^.*change-log-time-zone-rule['"$tab"' ]*:['"$tab"' ]*"\([^"]*\)".*/{ 360 sort $SORT_K_OPTIONS </dev/null 2>/dev/null || SORT_K_OPTIONS='+2 -4r +4 +0'
186 s//\1/; p; q
187 }
188 /^.*change-log-time-zone-rule['"$tab"' ]*:['"$tab"' ]*t.*/{
189 s//UTC0/; p; q
190 }
191 '
192 logTZ=`tail "$changelog" | sed -n "$extractTZ"`
193 case $logTZ in
194 ?*) TZ=$logTZ; export TZ
195 esac
196 fi
197
198 # If CVS is in use, examine its repository, not the normal RCS files.
199 if test ! -f CVS/Repository
200 then
201 rlog=rlog
202 repository=
203 else
204 rlog='cvs -q log'
205 repository=`sed 1q <CVS/Repository` || exit
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"
218 then
219 echo >&2 "$0: $repository: bad repository (see CVS/Repository)"
220 exit 1
221 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
229 esac
230
231 # With no arguments, examine all files under the RCS directory.
232 case $# in
233 0)
234 case $repository in
235 '')
236 oldIFS=$IFS
237 IFS=$nl
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
276 IFS=$oldIFS
277 esac
278 esac
279
280 llogout=$TMPDIR/rcs2log$$l
281 rlogout=$TMPDIR/rcs2log$$r
282 trap exit 1 2 13 15
283 trap "rm -f $llogout $rlogout; exit 1" 0
284
285 case $datearg in
286 ?*) $rlog $rlog_options "$datearg" ${1+"$@"} >$rlogout;;
287 '') $rlog $rlog_options ${1+"$@"} >$rlogout
288 esac || exit
289 361
290 362
291 # Get the full name of each author the logs mention, and set initialize_fullname 363 # Get the full name of each author the logs mention, and set initialize_fullname
292 # to awk code that initializes the `fullname' awk associative array. 364 # to awk code that initializes the `fullname' awk associative array.
293 # Warning: foreign authors (i.e. not known in the passwd file) are mishandled; 365 # Warning: foreign authors (i.e. not known in the passwd file) are mishandled;
301 case $loginFullnameMailaddrs in 373 case $loginFullnameMailaddrs in
302 *\"* | *\\*) 374 *\"* | *\\*)
303 sed 's/["\\]/\\&/g' >$llogout <<EOF || exit 375 sed 's/["\\]/\\&/g' >$llogout <<EOF || exit
304 $loginFullnameMailaddrs 376 $loginFullnameMailaddrs
305 EOF 377 EOF
306 loginFullnameMailaddrs=`cat $llogout` 378 loginFullnameMailaddrs=`cat $llogout`;;
307 esac 379 esac
308 380
309 oldIFS=$IFS 381 oldIFS=$IFS
310 IFS=$nl 382 IFS=$nl
311 for loginFullnameMailaddr in $loginFullnameMailaddrs 383 for loginFullnameMailaddr in $loginFullnameMailaddrs
312 do 384 do
313 case $loginFullnameMailaddr in 385 IFS=$tab
314 *"$tab"*) IFS=$tab;;
315 *) IFS=:
316 esac
317 set x $loginFullnameMailaddr 386 set x $loginFullnameMailaddr
318 login=$2 387 login=$2
319 fullname=$3 388 fullname=$3
320 mailaddr=$4 389 mailaddr=$4
321 initialize_fullname="$initialize_fullname 390 initialize_fullname="$initialize_fullname
322 fullname[\"$login\"] = \"$fullname\"" 391 fullname[\"$login\"] = \"$fullname\""
323 initialize_mailaddr="$initialize_mailaddr 392 initialize_mailaddr="$initialize_mailaddr
324 mailaddr[\"$login\"] = \"$mailaddr\"" 393 mailaddr[\"$login\"] = \"$mailaddr\""
325 done 394 done
326 IFS=$oldIFS 395 IFS=$oldIFS;;
327 esac 396 esac
328 397
329 case $llogout in 398 case $logins in
330 ?*) sort -u -o $llogout <<EOF || exit 399 ?*)
400 sort -u -o $llogout <<EOF
331 $logins 401 $logins
332 EOF 402 EOF
333 esac 403 ;;
404 '')
405 : ;;
406 esac >$llogout || exit
407
334 output_authors='/^date: / { 408 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 ~ /^[^;]*;$/) { 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 ~ /^[^;]*;$/) {
336 print substr($5, 1, length($5)-1) 410 print substr($5, 1, length($5)-1)
337 } 411 }
338 }' 412 }'
339 authors=` 413 authors=`
340 $AWK "$output_authors" <$rlogout | 414 $AWK "$output_authors" <"$rlogfile" | sort -u | comm -23 - $llogout
341 case $llogout in
342 '') sort -u;;
343 ?*) sort -u | comm -23 - $llogout
344 esac
345 ` 415 `
346 case $authors in 416 case $authors in
347 ?*) 417 ?*)
348 cat >$llogout <<EOF || exit 418 cat >$llogout <<EOF || exit
349 $authors 419 $authors
400 } 470 }
401 } 471 }
402 ' 472 '
403 473
404 initialize_fullname=` 474 initialize_fullname=`
405 ( 475 {
406 cat /etc/passwd 476 (getent passwd $authors) ||
407 for author in $authors 477 (
408 do nismatch $author passwd.org_dir 478 cat /etc/passwd
409 done 479 for author in $authors
410 ypmatch $authors passwd 480 do NIS_PATH= nismatch $author passwd.org_dir
411 ) 2>/dev/null | 481 done
482 ypmatch $authors passwd
483 )
484 } 2>/dev/null |
412 $AWK -F: "$awkscript" 485 $AWK -F: "$awkscript"
413 `$initialize_fullname 486 `$initialize_fullname;;
414 esac 487 esac
415 488
416 489
417 # Function to print a single log line. 490 # Function to print a single log line.
418 # We don't use awk functions, to stay compatible with old awk versions. 491 # We don't use awk functions, to stay compatible with old awk versions.
419 # `Log' is the log message (with \n replaced by \r). 492 # `Log' is the log message.
420 # `files' contains the affected files. 493 # `files' contains the affected files.
421 printlogline='{ 494 printlogline='{
422 495
423 # Following the GNU coding standards, rewrite 496 # Following the GNU coding standards, rewrite
424 # * file: (function): comment 497 # * file: (function): comment
425 # to 498 # to
426 # * file (function): comment 499 # * file (function): comment
427 if (Log ~ /^\([^)]*\): /) { 500 if (Log ~ /^\([^)]*\):[\t\n ]/) {
428 i = index(Log, ")") 501 i = index(Log, ")")
429 files = files " " substr(Log, 1, i) 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
430 Log = substr(Log, i+3) 508 Log = substr(Log, i+3)
431 } 509 }
432 510
433 # If "label: comment" is too long, break the line after the ":". 511 # If "label: comment" is too long, break the line after the ":".
434 sep = " " 512 sep = " "
435 if ('"$length"' <= '"$indent"' + 1 + length(files) + index(Log, CR)) sep = "\n" indent_string 513 i = index(Log, "\n")
514 if ('"$length"' <= '"$indent"' + 1 + length(files) + i) sep = "\n" indent_string
436 515
437 # Print the label. 516 # Print the label.
438 printf "%s*%s:", indent_string, files 517 printf "%s*%s:", indent_string, files
439 518
440 # Print each line of the log, transliterating \r to \n. 519 # Print each line of the log.
441 while ((i = index(Log, CR)) != 0) { 520 while (i) {
442 logline = substr(Log, 1, i-1) 521 logline = substr(Log, 1, i-1)
443 if (logline ~ /[^'"$tab"' ]/) { 522 if (logline ~ /[^'"$tab"' ]/) {
444 printf "%s%s\n", sep, logline 523 printf "%s%s\n", sep, logline
445 } else { 524 } else {
446 print "" 525 print ""
447 } 526 }
448 sep = indent_string 527 sep = indent_string
449 Log = substr(Log, i+1) 528 Log = substr(Log, i+1)
529 i = index(Log, "\n")
450 } 530 }
451 }' 531 }'
452 532
453 # Pattern to match the `revision' line of rlog output. 533 # 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"' ]*$' 534 rlog_revision_pattern='^revision [0-9]+\.[0-9]+(\.[0-9]+\.[0-9]+)*(['"$tab"' ]+locked by: [^'"$tab"' $,.0-9:;@]*[^'"$tab"' $,:;@][^'"$tab"' $,.0-9:;@]*;)?['"$tab"' ]*$'
465 case $hostname in 545 case $hostname in
466 *.*) ;; 546 *.*) ;;
467 *) 547 *)
468 domainname=`(domainname) 2>/dev/null` && 548 domainname=`(domainname) 2>/dev/null` &&
469 case $domainname in 549 case $domainname in
470 *.*) hostname=$hostname.$domainname 550 *.*) hostname=$hostname.$domainname;;
471 esac 551 esac;;
472 esac 552 esac;;
473 esac 553 esac
474 554
475 555
476 # Process the rlog output, generating ChangeLog style entries. 556 # Process the rlog output, generating ChangeLog style entries.
477 557
478 # First, reformat the rlog output so that each line contains one log entry. 558 # First, reformat the rlog output so that each line contains one log entry.
479 # Transliterate \n to \r so that multiline entries fit on a single line. 559 # Transliterate \n to SOH so that multiline entries fit on a single line.
480 # Discard irrelevant rlog output. 560 # Discard irrelevant rlog output.
481 $AWK <$rlogout ' 561 $AWK '
482 BEGIN { repository = "'"$repository"'" } 562 BEGIN {
483 /^RCS file:/ { 563 pository = "'"$pository"'"
484 if (repository != "") { 564 SOH="'"$SOH"'"
485 filename = $3 565 }
486 if (substr(filename, 1, length(repository) + 1) == repository "/") { 566 /^RCS file: / {
487 filename = substr(filename, length(repository) + 2) 567 if (pository != "") {
568 filename = substr($0, 11)
569 if (substr(filename, 1, length(pository)) == pository) {
570 filename = substr(filename, length(pository) + 1)
488 } 571 }
489 if (filename ~ /,v$/) { 572 if (filename ~ /,v$/) {
490 filename = substr(filename, 1, length(filename) - 2) 573 filename = substr(filename, 1, length(filename) - 2)
491 } 574 }
492 if (filename ~ /(^|\/)Attic\/[^\/]*$/) { 575 if (filename ~ /(^|\/)Attic\/[^\/]*$/) {
495 filename = substr(filename, 1, i - 6) substr(filename, i + 1) 578 filename = substr(filename, 1, i - 6) substr(filename, i + 1)
496 } 579 }
497 } 580 }
498 rev = "?" 581 rev = "?"
499 } 582 }
500 /^Working file:/ { if (repository == "") filename = $3 } 583 /^Working file: / { if (repository == "") filename = substr($0, 15) }
501 /'"$rlog_revision_pattern"'/, /^(-----------*|===========*)$/ { 584 /'"$rlog_revision_pattern"'/, /^(-----------*|===========*)$/ {
502 if ($0 ~ /'"$rlog_revision_pattern"'/) { 585 line = $0
586 if (line ~ /'"$rlog_revision_pattern"'/) {
503 rev = $2 587 rev = $2
504 next 588 next
505 } 589 }
506 if ($0 ~ /^date: [0-9][- +\/0-9:]*;/) { 590 if (line ~ /^date: [0-9][- +\/0-9:]*;/) {
507 date = $2 591 date = $2
508 if (date ~ /\//) { 592 if (date ~ /\//) {
509 # This is a traditional RCS format date YYYY/MM/DD. 593 # This is a traditional RCS format date YYYY/MM/DD.
510 # Replace "/"s with "-"s to get ISO format. 594 # Replace "/"s with "-"s to get ISO format.
511 newdate = "" 595 newdate = ""
515 } 599 }
516 date = newdate date 600 date = newdate date
517 } 601 }
518 time = substr($3, 1, length($3) - 1) 602 time = substr($3, 1, length($3) - 1)
519 author = substr($5, 1, length($5)-1) 603 author = substr($5, 1, length($5)-1)
520 printf "%s %s %s %s %s %c", filename, rev, date, time, author, 13 604 printf "%s%s%s%s%s%s%s%s%s%s", filename, SOH, rev, SOH, date, SOH, time, SOH, author, SOH
521 rev = "?" 605 rev = "?"
522 next 606 next
523 } 607 }
524 if ($0 ~ /^branches: /) { next } 608 if (line ~ /^branches: /) { next }
525 if ($0 ~ /^(-----------*|===========*)$/) { print ""; next } 609 if (line ~ /^(-----------*|===========*)$/) { print ""; next }
526 if ($0 == "Initial revision" || $0 ~ /^file .+ was initially added on branch .+\.$/) { 610 if (line == "Initial revision" || line ~ /^file .+ was initially added on branch .+\.$/) {
527 $0 = "New file." 611 line = "New file."
528 } 612 }
529 printf "%s%c", $0, 13 613 printf "%s%s", line, SOH
530 } 614 }
531 ' | 615 ' <"$rlogfile" |
532 616
533 # Now each line is of the form 617 # Now each line is of the form
534 # FILENAME REVISION YYYY-MM-DD HH:MM:SS[+-TIMEZONE] AUTHOR \rLOG 618 # FILENAME@REVISION@YYYY-MM-DD@HH:MM:SS[+-TIMEZONE]@AUTHOR@LOG
535 # where \r stands for a carriage return, 619 # where @ stands for an SOH (octal code 001),
536 # and each line of the log is terminated by \r instead of \n. 620 # and each line of LOG is terminated by SOH instead of \n.
537 # Sort the log entries, first by date+time (in reverse order), 621 # Sort the log entries, first by date+time (in reverse order),
538 # then by author, then by log entry, and finally by file name and revision 622 # then by author, then by log entry, and finally by file name and revision
539 # (just in case). 623 # (just in case).
540 sort +2 -4r +4 +0 | 624 sort -t"$SOH" $SORT_K_OPTIONS |
541 625
542 # Finally, reformat the sorted log entries. 626 # Finally, reformat the sorted log entries.
543 $AWK ' 627 $AWK -F"$SOH" '
544 BEGIN { 628 BEGIN {
545 logTZ = "'"$logTZ"'" 629 logTZ = "'"$logTZ"'"
546 revision = "'"$revision"'" 630 revision = "'"$revision"'"
547
548 # Some awk variants do not understand "\r" or "\013", so we have to
549 # put a carriage return directly in the file.
550 CR="
551 " # <-- There is a single CR between the " chars here.
552 631
553 # Initialize the fullname and mailaddr associative arrays. 632 # Initialize the fullname and mailaddr associative arrays.
554 '"$initialize_fullname"' 633 '"$initialize_fullname"'
555 '"$initialize_mailaddr"' 634 '"$initialize_mailaddr"'
556 635
563 while (1 <= i--) 642 while (1 <= i--)
564 indent_string = indent_string " " 643 indent_string = indent_string " "
565 } 644 }
566 645
567 { 646 {
568 newlog = substr($0, 1 + index($0, CR)) 647 newlog = ""
648 for (i = 6; i < NF; i++) newlog = newlog $i "\n"
569 649
570 # Ignore log entries prefixed by "#". 650 # Ignore log entries prefixed by "#".
571 if (newlog ~ /^#/) { next } 651 if (newlog ~ /^#/) { next }
572 652
573 if (Log != newlog || date != $3 || author != $5) { 653 if (Log != newlog || date != $3 || author != $5) {
587 if (newlog ~ /^\{[^'"$tab"' }]*}['"$tab"' ]/) { 667 if (newlog ~ /^\{[^'"$tab"' }]*}['"$tab"' ]/) {
588 i = index(newlog, "}") 668 i = index(newlog, "}")
589 newclumpname = substr(newlog, 1, i) 669 newclumpname = substr(newlog, 1, i)
590 while (substr(newlog, i+1) ~ /^['"$tab"' ]/) i++ 670 while (substr(newlog, i+1) ~ /^['"$tab"' ]/) i++
591 newlog = substr(newlog, i+1) 671 newlog = substr(newlog, i+1)
592 if (clumpname == newclumpname) sep = "" 672 if (clumpname == newclumpname && date == $3 && author == $5) sep = ""
593 } 673 }
594 printf sep 674 printf sep
595 clumpname = newclumpname 675 clumpname = newclumpname
596 676
597 # Get ready for the next log. 677 # Get ready for the next log.
642 ' && 722 ' &&
643 723
644 724
645 # Exit successfully. 725 # Exit successfully.
646 726
647 exec rm -f $llogout $rlogout 727 exec rm -fr $logdir
648 728
649 # Local Variables: 729 # Local Variables:
650 # tab-width:4 730 # tab-width:4
651 # End: 731 # End: