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: |
