Mercurial > hg > xemacs-beta
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: |