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