diff options
| author | Paul Eggert | 2001-09-05 23:07:46 +0000 |
|---|---|---|
| committer | Paul Eggert | 2001-09-05 23:07:46 +0000 |
| commit | 1bd57c395666fb60cfca4a256d735a276174cf39 (patch) | |
| tree | ec7baaa2be2609de4148e428635a0cff16810cee /lib-src | |
| parent | 3b74127de1a11177e910cab532fabb7d491dd157 (diff) | |
| download | emacs-1bd57c395666fb60cfca4a256d735a276174cf39.tar.gz emacs-1bd57c395666fb60cfca4a256d735a276174cf39.zip | |
(Help, mainline code): Add new option -L FILE.
(Copyright): Update year.
(LANG, LANGUAGE, LC_ALL, LC_COLLATE, LC_CTYPE, LC_MESSAGES,
LC_NUMERIC, LC_TIME): New shell vars, to make sure we live in the C locale.
(mainline code): Handle nonstandard -u option differently, by
transforming it to standard form. Check for "Working file: ", not
"Working file:". Allow file names with spaces.
(SOH, rlogfile): New shell vars.
(rlogout): Remove. Its old functionality is mostly migrated to rlogfile.
Append ';;' to the last arm of every case statement, for portability to
ancient broken BSD shells.
(logins): Fix bug; was not being computed at all, lowering performance.
(pository): New var. This fixes some bugs where repositories are
remote, or have trailing slashes.
(authors): $llogout is never an empty shell var, so don't worry about that
possibility.
(printlogline, mainline code): Fix bug with SOH's being put into the output.
Diffstat (limited to 'lib-src')
| -rwxr-xr-x | lib-src/rcs2log | 445 |
1 files changed, 245 insertions, 200 deletions
diff --git a/lib-src/rcs2log b/lib-src/rcs2log index f1bd89dc715..eabd369a9d6 100755 --- a/lib-src/rcs2log +++ b/lib-src/rcs2log | |||
| @@ -18,6 +18,7 @@ Options: | |||
| 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). |
| @@ -28,9 +29,9 @@ Options: | |||
| 28 | 29 | ||
| 29 | Report bugs to <bug-gnu-emacs@gnu.org>.' | 30 | Report bugs to <bug-gnu-emacs@gnu.org>.' |
| 30 | 31 | ||
| 31 | Id='$Id: rcs2log,v 1.46 2001/01/03 12:04:06 gerd Exp $' | 32 | Id='$Id: rcs2log,v 1.47 2001/07/20 09:05:26 gerd Exp eggert $' |
| 32 | 33 | ||
| 33 | # Copyright 1992, 93, 94, 95, 96, 97, 1998, 2001 | 34 | # Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2001 |
| 34 | # Free Software Foundation, Inc. | 35 | # Free Software Foundation, Inc. |
| 35 | 36 | ||
| 36 | # 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 |
| @@ -48,13 +49,29 @@ Id='$Id: rcs2log,v 1.46 2001/01/03 12:04:06 gerd Exp $' | |||
| 48 | # Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 49 | # Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| 49 | # Boston, MA 02111-1307, USA. | 50 | # Boston, MA 02111-1307, USA. |
| 50 | 51 | ||
| 51 | Copyright='Copyright 1998 Free Software Foundation, Inc. | 52 | Copyright='Copyright 2001 Free Software Foundation, Inc. |
| 52 | 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. |
| 53 | You may redistribute copies of this program | 54 | You may redistribute copies of this program |
| 54 | under the terms of the GNU General Public License. | 55 | under the terms of the GNU General Public License. |
| 55 | For more information about these matters, see the files named COPYING. | 56 | For more information about these matters, see the files named COPYING. |
| 56 | Author: Paul Eggert <eggert@twinsun.com>' | 57 | Author: Paul Eggert <eggert@twinsun.com>' |
| 57 | 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 | ||
| 58 | tab=' ' | 75 | tab=' ' |
| 59 | nl=' | 76 | nl=' |
| 60 | ' | 77 | ' |
| @@ -75,6 +92,7 @@ logTZ= # time zone for log dates (if empty, use local time) | |||
| 75 | recursive= # t if we want recursive rlog | 92 | recursive= # t if we want recursive rlog |
| 76 | revision= # t if we want revision numbers | 93 | revision= # t if we want revision numbers |
| 77 | rlog_options= # options to pass to rlog | 94 | rlog_options= # options to pass to rlog |
| 95 | rlogfile= # log file to read from | ||
| 78 | tabwidth=8 # width of horizontal tab | 96 | tabwidth=8 # width of horizontal tab |
| 79 | 97 | ||
| 80 | while : | 98 | while : |
| @@ -84,17 +102,16 @@ do | |||
| 84 | -i) indent=${2?}; shift;; | 102 | -i) indent=${2?}; shift;; |
| 85 | -h) hostname=${2?}; shift;; | 103 | -h) hostname=${2?}; shift;; |
| 86 | -l) length=${2?}; shift;; | 104 | -l) length=${2?}; shift;; |
| 105 | -L) rlogfile=${2?}; shift;; | ||
| 87 | -[nu]) # -n is obsolescent; it is replaced by -u. | 106 | -[nu]) # -n is obsolescent; it is replaced by -u. |
| 88 | case $1 in | 107 | case $1 in |
| 89 | -n) case ${2?}${3?}${4?} in | 108 | -n) case ${2?}${3?}${4?} in |
| 90 | *"$tab"* | *"$nl"*) | 109 | *"$tab"* | *"$nl"*) |
| 91 | echo >&2 "$0: -n '$2' '$3' '$4': tabs, newlines not allowed" | 110 | echo >&2 "$0: -n '$2' '$3' '$4': tabs, newlines not allowed" |
| 92 | exit 1 | 111 | exit 1;; |
| 93 | esac | ||
| 94 | case $loginFullnameMailaddrs in | ||
| 95 | '') loginFullnameMailaddrs=$2$tab$3$tab$4;; | ||
| 96 | ?*) loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2$tab$3$tab$4 | ||
| 97 | esac | 112 | esac |
| 113 | login=$2 | ||
| 114 | lfm=$2$tab$3$tab$4 | ||
| 98 | shift; shift; shift;; | 115 | shift; shift; shift;; |
| 99 | -u) | 116 | -u) |
| 100 | # If $2 is not tab-separated, use colon for separator. | 117 | # If $2 is not tab-separated, use colon for separator. |
| @@ -105,33 +122,39 @@ do | |||
| 105 | *"$tab"*) | 122 | *"$tab"*) |
| 106 | t=$tab;; | 123 | t=$tab;; |
| 107 | *) | 124 | *) |
| 108 | t=: | 125 | t=':';; |
| 109 | esac | 126 | esac |
| 110 | case $2 in | 127 | case $2 in |
| 111 | *"$t"*"$t"*"$t"*) | 128 | *"$t"*"$t"*"$t"*) |
| 112 | echo >&2 "$0: -u '$2': too many fields" | 129 | echo >&2 "$0: -u '$2': too many fields" |
| 113 | exit 1;; | 130 | exit 1;; |
| 114 | *"$t"*"$t"*) | 131 | *"$t"*"$t"*) |
| 115 | ;; | 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 | `;; | ||
| 116 | *) | 140 | *) |
| 117 | echo >&2 "$0: -u '$2': not enough fields" | 141 | echo >&2 "$0: -u '$2': not enough fields" |
| 118 | exit 1 | 142 | exit 1;; |
| 119 | esac | ||
| 120 | case $loginFullnameMailaddrs in | ||
| 121 | '') loginFullnameMailaddrs=$2;; | ||
| 122 | ?*) loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2 | ||
| 123 | esac | 143 | esac |
| 124 | shift | 144 | shift;; |
| 125 | esac | 145 | esac |
| 126 | case $logins in | 146 | case $logins in |
| 127 | '') logins=$login;; | 147 | '') logins=$login;; |
| 128 | ?*) logins=$logins$nl$login | 148 | ?*) logins=$logins$nl$login;; |
| 129 | esac | 149 | esac |
| 130 | ;; | 150 | case $loginFullnameMailaddrs in |
| 151 | '') loginFullnameMailaddrs=$lfm;; | ||
| 152 | ?*) loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$lfm;; | ||
| 153 | esac;; | ||
| 131 | -r) | 154 | -r) |
| 132 | case $rlog_options in | 155 | case $rlog_options in |
| 133 | '') rlog_options=${2?};; | 156 | '') rlog_options=${2?};; |
| 134 | ?*) rlog_options=$rlog_options$nl${2?} | 157 | ?*) rlog_options=$rlog_options$nl${2?};; |
| 135 | esac | 158 | esac |
| 136 | shift;; | 159 | shift;; |
| 137 | -R) recursive=t;; | 160 | -R) recursive=t;; |
| @@ -145,9 +168,9 @@ do | |||
| 145 | -*) echo >&2 "Usage: $0 [OPTION]... [FILE ...]$nl$Help" | 168 | -*) echo >&2 "Usage: $0 [OPTION]... [FILE ...]$nl$Help" |
| 146 | case $1 in | 169 | case $1 in |
| 147 | --help) exit 0;; | 170 | --help) exit 0;; |
| 148 | *) exit 1 | 171 | *) exit 1;; |
| 149 | esac;; | 172 | esac;; |
| 150 | *) break | 173 | *) break;; |
| 151 | esac | 174 | esac |
| 152 | shift | 175 | shift |
| 153 | done | 176 | done |
| @@ -159,159 +182,176 @@ month_data=' | |||
| 159 | m[9]="Oct"; m[10]="Nov"; m[11]="Dec" | 182 | m[9]="Oct"; m[10]="Nov"; m[11]="Dec" |
| 160 | ' | 183 | ' |
| 161 | 184 | ||
| 185 | logdir=$TMPDIR/rcs2log$$ | ||
| 186 | llogout=$logdir/l | ||
| 187 | trap exit 1 2 13 15 | ||
| 188 | trap "rm -fr $logdir 2>/dev/null" 0 | ||
| 189 | (umask 077 && exec mkdir $logdir) || exit | ||
| 162 | 190 | ||
| 163 | # Put rlog output into $rlogout. | 191 | # If no rlog-format log file is given, generate one into $rlogfile. |
| 164 | 192 | case $rlogfile in | |
| 165 | # If no rlog options are given, | ||
| 166 | # log the revisions checked in since the first ChangeLog entry. | ||
| 167 | # Since ChangeLog is only by date, some of these revisions may be duplicates of | ||
| 168 | # what's already in ChangeLog; it's the user's responsibility to remove them. | ||
| 169 | case $rlog_options in | ||
| 170 | '') | 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. | ||
| 171 | if test -s "$changelog" | 228 | if test -s "$changelog" |
| 172 | then | 229 | then |
| 173 | e=' | 230 | extractTZ=' |
| 174 | /^[0-9]+-[0-9][0-9]-[0-9][0-9]/{ | 231 | /^.*change-log-time-zone-rule['"$tab"' ]*:['"$tab"' ]*"\([^"]*\)".*/{ |
| 175 | # ISO 8601 date | 232 | s//\1/; p; q |
| 176 | print $1 | ||
| 177 | exit | ||
| 178 | } | 233 | } |
| 179 | /^... ... [ 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.*/{ |
| 180 | # old-fashioned date and time (Emacs 19.31 and earlier) | 235 | s//UTC0/; p; q |
| 181 | '"$month_data"' | ||
| 182 | year = $5 | ||
| 183 | for (i=0; i<=11; i++) if (m[i] == $2) break | ||
| 184 | dd = $3 | ||
| 185 | printf "%d-%02d-%02d\n", year, i+1, dd | ||
| 186 | exit | ||
| 187 | } | 236 | } |
| 188 | ' | 237 | ' |
| 189 | d=`$AWK "$e" <"$changelog"` || exit | 238 | logTZ=`tail "$changelog" | sed -n "$extractTZ"` |
| 190 | case $d in | 239 | case $logTZ in |
| 191 | ?*) datearg="-d>$d" | 240 | ?*) TZ=$logTZ; export TZ;; |
| 192 | esac | 241 | esac |
| 193 | fi | 242 | fi |
| 194 | esac | ||
| 195 | 243 | ||
| 196 | # Use TZ specified by ChangeLog local variable, if any. | 244 | # If CVS is in use, examine its repository, not the normal RCS files. |
| 197 | if test -s "$changelog" | 245 | if test ! -f CVS/Repository |
| 198 | then | 246 | then |
| 199 | extractTZ=' | 247 | rlog=rlog |
| 200 | /^.*change-log-time-zone-rule['"$tab"' ]*:['"$tab"' ]*"\([^"]*\)".*/{ | 248 | repository= |
| 201 | s//\1/; p; q | 249 | else |
| 202 | } | 250 | rlog='cvs -q log' |
| 203 | /^.*change-log-time-zone-rule['"$tab"' ]*:['"$tab"' ]*t.*/{ | 251 | repository=`sed 1q <CVS/Repository` || exit |
| 204 | s//UTC0/; p; q | 252 | test ! -f CVS/Root || CVSROOT=`cat <CVS/Root` || exit |
| 205 | } | 253 | case $CVSROOT in |
| 206 | ' | 254 | *:/*:/*) |
| 207 | logTZ=`tail "$changelog" | sed -n "$extractTZ"` | 255 | echo >&2 "$0: $CVSROOT: CVSROOT has multiple ':/'s" |
| 208 | case $logTZ in | 256 | exit 1;; |
| 209 | ?*) TZ=$logTZ; export TZ | 257 | *:/*) |
| 210 | esac | 258 | # remote repository |
| 211 | fi | 259 | pository=`expr "X$repository" : '.*:\(/.*\)'`;; |
| 212 | 260 | *) | |
| 213 | # If CVS is in use, examine its repository, not the normal RCS files. | 261 | # local repository |
| 214 | if test ! -f CVS/Repository | 262 | case $repository in |
| 215 | then | 263 | /*) ;; |
| 216 | rlog=rlog | 264 | *) repository=${CVSROOT?}/$repository;; |
| 217 | repository= | 265 | esac |
| 218 | else | 266 | if test ! -d "$repository" |
| 219 | rlog='cvs -q log' | 267 | then |
| 220 | repository=`sed 1q <CVS/Repository` || exit | 268 | echo >&2 "$0: $repository: bad repository (see CVS/Repository)" |
| 221 | test ! -f CVS/Root || CVSROOT=`cat <CVS/Root` || exit | 269 | exit 1 |
| 222 | case $CVSROOT in | 270 | fi |
| 223 | *:/*) | 271 | pository=$repository;; |
| 224 | # remote repository | ||
| 225 | ;; | ||
| 226 | *) | ||
| 227 | # local repository | ||
| 228 | case $repository in | ||
| 229 | /*) ;; | ||
| 230 | *) repository=${CVSROOT?}/$repository | ||
| 231 | esac | 272 | esac |
| 232 | if test ! -d "$repository" | ||
| 233 | then | ||
| 234 | echo >&2 "$0: $repository: bad repository (see CVS/Repository)" | ||
| 235 | exit 1 | ||
| 236 | fi | ||
| 237 | esac | ||
| 238 | fi | ||
| 239 | 273 | ||
| 240 | # Use $rlog's -zLT option, if $rlog supports it. | 274 | # Ensure that $pository ends in exactly one slash. |
| 241 | case `$rlog -zLT 2>&1` in | 275 | while : |
| 242 | *' option'*) ;; | 276 | do |
| 243 | *) | 277 | case $pository in |
| 244 | case $rlog_options in | 278 | *//) pository=`expr "X$pository" : 'X\(.*\)/'`;; |
| 245 | '') rlog_options=-zLT;; | 279 | */) break;; |
| 246 | ?*) rlog_options=-zLT$nl$rlog_options | 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;; | ||
| 247 | esac | 294 | esac |
| 248 | esac | ||
| 249 | 295 | ||
| 250 | # With no arguments, examine all files under the RCS directory. | 296 | # With no arguments, examine all files under the RCS directory. |
| 251 | case $# in | 297 | case $# in |
| 252 | 0) | 298 | 0) |
| 253 | case $repository in | 299 | case $repository in |
| 254 | '') | 300 | '') |
| 255 | oldIFS=$IFS | 301 | oldIFS=$IFS |
| 256 | IFS=$nl | 302 | IFS=$nl |
| 257 | case $recursive in | 303 | case $recursive in |
| 258 | t) | 304 | t) |
| 259 | RCSdirs=`find . -name RCS -type d -print` | 305 | RCSdirs=`find . -name RCS -type d -print` |
| 260 | filesFromRCSfiles='s|,v$||; s|/RCS/|/|; s|^\./||' | 306 | filesFromRCSfiles='s|,v$||; s|/RCS/|/|; s|^\./||' |
| 261 | files=` | 307 | files=` |
| 262 | { | 308 | { |
| 263 | case $RCSdirs in | 309 | case $RCSdirs in |
| 264 | ?*) find $RCSdirs \ | 310 | ?*) find $RCSdirs \ |
| 265 | -type f \ | 311 | -type f \ |
| 266 | ! -name '*_' \ | 312 | ! -name '*_' \ |
| 267 | ! -name ',*,' \ | 313 | ! -name ',*,' \ |
| 268 | ! -name '.*_' \ | 314 | ! -name '.*_' \ |
| 269 | ! -name .rcsfreeze.log \ | 315 | ! -name .rcsfreeze.log \ |
| 270 | ! -name .rcsfreeze.ver \ | 316 | ! -name .rcsfreeze.ver \ |
| 271 | 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;; | ||
| 272 | esac | 334 | esac |
| 273 | find . -name '*,v' -print | 335 | case $files in |
| 274 | } | | 336 | '') files=$file;; |
| 275 | sort -u | | 337 | ?*) files=$files$nl$file;; |
| 276 | sed "$filesFromRCSfiles" | 338 | esac |
| 277 | `;; | 339 | done |
| 278 | *) | ||
| 279 | files= | ||
| 280 | for file in RCS/.* RCS/* .*,v *,v | ||
| 281 | do | ||
| 282 | case $file in | ||
| 283 | RCS/. | RCS/.. | RCS/,*, | RCS/*_) continue;; | ||
| 284 | RCS/.rcsfreeze.log | RCS/.rcsfreeze.ver) continue;; | ||
| 285 | RCS/.\* | RCS/\* | .\*,v | \*,v) test -f "$file" || continue;; | ||
| 286 | RCS/*,v | RCS/.*,v) ;; | ||
| 287 | RCS/* | RCS/.*) test -f "$file" || continue | ||
| 288 | esac | ||
| 289 | case $files in | 340 | case $files in |
| 290 | '') files=$file;; | 341 | '') exit 0;; |
| 291 | ?*) files=$files$nl$file | 342 | esac;; |
| 292 | esac | ||
| 293 | done | ||
| 294 | case $files in | ||
| 295 | '') exit 0 | ||
| 296 | esac | 343 | esac |
| 297 | esac | 344 | set x $files |
| 298 | set x $files | 345 | shift |
| 299 | shift | 346 | IFS=$oldIFS;; |
| 300 | IFS=$oldIFS | 347 | esac;; |
| 301 | esac | 348 | esac |
| 302 | esac | ||
| 303 | |||
| 304 | logdir=$TMPDIR/rcs2log$$ | ||
| 305 | llogout=$logdir/l | ||
| 306 | rlogout=$logdir/r | ||
| 307 | trap exit 1 2 13 15 | ||
| 308 | trap "rm -fr $logdir 2>/dev/null" 0 | ||
| 309 | (umask 077 && exec mkdir $logdir) || exit | ||
| 310 | 349 | ||
| 311 | case $datearg in | 350 | case $datearg in |
| 312 | ?*) $rlog $rlog_options "$datearg" ${1+"$@"} >$rlogout;; | 351 | ?*) $rlog $rlog_options "$datearg" ${1+"$@"} >$rlogfile;; |
| 313 | '') $rlog $rlog_options ${1+"$@"} >$rlogout | 352 | '') $rlog $rlog_options ${1+"$@"} >$rlogfile;; |
| 314 | esac || exit | 353 | esac || exit;; |
| 354 | esac | ||
| 315 | 355 | ||
| 316 | 356 | ||
| 317 | # Get the full name of each author the logs mention, and set initialize_fullname | 357 | # Get the full name of each author the logs mention, and set initialize_fullname |
| @@ -329,17 +369,14 @@ case $loginFullnameMailaddrs in | |||
| 329 | sed 's/["\\]/\\&/g' >$llogout <<EOF || exit | 369 | sed 's/["\\]/\\&/g' >$llogout <<EOF || exit |
| 330 | $loginFullnameMailaddrs | 370 | $loginFullnameMailaddrs |
| 331 | EOF | 371 | EOF |
| 332 | loginFullnameMailaddrs=`cat $llogout` | 372 | loginFullnameMailaddrs=`cat $llogout`;; |
| 333 | esac | 373 | esac |
| 334 | 374 | ||
| 335 | oldIFS=$IFS | 375 | oldIFS=$IFS |
| 336 | IFS=$nl | 376 | IFS=$nl |
| 337 | for loginFullnameMailaddr in $loginFullnameMailaddrs | 377 | for loginFullnameMailaddr in $loginFullnameMailaddrs |
| 338 | do | 378 | do |
| 339 | case $loginFullnameMailaddr in | 379 | IFS=$tab |
| 340 | *"$tab"*) IFS=$tab;; | ||
| 341 | *) IFS=: | ||
| 342 | esac | ||
| 343 | set x $loginFullnameMailaddr | 380 | set x $loginFullnameMailaddr |
| 344 | login=$2 | 381 | login=$2 |
| 345 | fullname=$3 | 382 | fullname=$3 |
| @@ -349,25 +386,26 @@ EOF | |||
| 349 | initialize_mailaddr="$initialize_mailaddr | 386 | initialize_mailaddr="$initialize_mailaddr |
| 350 | mailaddr[\"$login\"] = \"$mailaddr\"" | 387 | mailaddr[\"$login\"] = \"$mailaddr\"" |
| 351 | done | 388 | done |
| 352 | IFS=$oldIFS | 389 | IFS=$oldIFS;; |
| 353 | esac | 390 | esac |
| 354 | 391 | ||
| 355 | case $llogout in | 392 | case $logins in |
| 356 | ?*) sort -u -o $llogout <<EOF || exit | 393 | ?*) |
| 394 | sort -u -o $llogout <<EOF | ||
| 357 | $logins | 395 | $logins |
| 358 | EOF | 396 | EOF |
| 359 | esac | 397 | ;; |
| 398 | '') | ||
| 399 | : ;; | ||
| 400 | esac >$llogout || exit | ||
| 401 | |||
| 360 | output_authors='/^date: / { | 402 | output_authors='/^date: / { |
| 361 | 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 ~ /^[^;]*;$/) { | 403 | 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 ~ /^[^;]*;$/) { |
| 362 | print substr($5, 1, length($5)-1) | 404 | print substr($5, 1, length($5)-1) |
| 363 | } | 405 | } |
| 364 | }' | 406 | }' |
| 365 | authors=` | 407 | authors=` |
| 366 | $AWK "$output_authors" <$rlogout | | 408 | $AWK "$output_authors" <"$rlogfile" | sort -u | comm -23 - $llogout |
| 367 | case $llogout in | ||
| 368 | '') sort -u;; | ||
| 369 | ?*) sort -u | comm -23 - $llogout | ||
| 370 | esac | ||
| 371 | ` | 409 | ` |
| 372 | case $authors in | 410 | case $authors in |
| 373 | ?*) | 411 | ?*) |
| @@ -439,13 +477,13 @@ EOF | |||
| 439 | ) | 477 | ) |
| 440 | } 2>/dev/null | | 478 | } 2>/dev/null | |
| 441 | $AWK -F: "$awkscript" | 479 | $AWK -F: "$awkscript" |
| 442 | `$initialize_fullname | 480 | `$initialize_fullname;; |
| 443 | esac | 481 | esac |
| 444 | 482 | ||
| 445 | 483 | ||
| 446 | # Function to print a single log line. | 484 | # Function to print a single log line. |
| 447 | # We don't use awk functions, to stay compatible with old awk versions. | 485 | # We don't use awk functions, to stay compatible with old awk versions. |
| 448 | # `Log' is the log message (with \n replaced by \001). | 486 | # `Log' is the log message. |
| 449 | # `files' contains the affected files. | 487 | # `files' contains the affected files. |
| 450 | printlogline='{ | 488 | printlogline='{ |
| 451 | 489 | ||
| @@ -455,19 +493,25 @@ printlogline='{ | |||
| 455 | # * file (function): comment | 493 | # * file (function): comment |
| 456 | if (Log ~ /^\([^)]*\): /) { | 494 | if (Log ~ /^\([^)]*\): /) { |
| 457 | i = index(Log, ")") | 495 | i = index(Log, ")") |
| 458 | files = files " " substr(Log, 1, i) | 496 | filefunc = substr(Log, 1, i) |
| 497 | while ((j = index(filefunc, "\n"))) { | ||
| 498 | files = files " " substr(filefunc, 1, j-1) | ||
| 499 | filefunc = substr(filefunc, j+1) | ||
| 500 | } | ||
| 501 | files = files " " filefunc | ||
| 459 | Log = substr(Log, i+3) | 502 | Log = substr(Log, i+3) |
| 460 | } | 503 | } |
| 461 | 504 | ||
| 462 | # If "label: comment" is too long, break the line after the ":". | 505 | # If "label: comment" is too long, break the line after the ":". |
| 463 | sep = " " | 506 | sep = " " |
| 464 | if ('"$length"' <= '"$indent"' + 1 + length(files) + index(Log, SOH)) sep = "\n" indent_string | 507 | i = index(Log, "\n") |
| 508 | if ('"$length"' <= '"$indent"' + 1 + length(files) + i) sep = "\n" indent_string | ||
| 465 | 509 | ||
| 466 | # Print the label. | 510 | # Print the label. |
| 467 | printf "%s*%s:", indent_string, files | 511 | printf "%s*%s:", indent_string, files |
| 468 | 512 | ||
| 469 | # Print each line of the log, transliterating \001 to \n. | 513 | # Print each line of the log. |
| 470 | while ((i = index(Log, SOH)) != 0) { | 514 | while (i) { |
| 471 | logline = substr(Log, 1, i-1) | 515 | logline = substr(Log, 1, i-1) |
| 472 | if (logline ~ /[^'"$tab"' ]/) { | 516 | if (logline ~ /[^'"$tab"' ]/) { |
| 473 | printf "%s%s\n", sep, logline | 517 | printf "%s%s\n", sep, logline |
| @@ -476,6 +520,7 @@ printlogline='{ | |||
| 476 | } | 520 | } |
| 477 | sep = indent_string | 521 | sep = indent_string |
| 478 | Log = substr(Log, i+1) | 522 | Log = substr(Log, i+1) |
| 523 | i = index(Log, "\n") | ||
| 479 | } | 524 | } |
| 480 | }' | 525 | }' |
| 481 | 526 | ||
| @@ -496,24 +541,27 @@ case $hostname in | |||
| 496 | *) | 541 | *) |
| 497 | domainname=`(domainname) 2>/dev/null` && | 542 | domainname=`(domainname) 2>/dev/null` && |
| 498 | case $domainname in | 543 | case $domainname in |
| 499 | *.*) hostname=$hostname.$domainname | 544 | *.*) hostname=$hostname.$domainname;; |
| 500 | esac | 545 | esac;; |
| 501 | esac | 546 | esac;; |
| 502 | esac | 547 | esac |
| 503 | 548 | ||
| 504 | 549 | ||
| 505 | # Process the rlog output, generating ChangeLog style entries. | 550 | # Process the rlog output, generating ChangeLog style entries. |
| 506 | 551 | ||
| 507 | # First, reformat the rlog output so that each line contains one log entry. | 552 | # First, reformat the rlog output so that each line contains one log entry. |
| 508 | # Transliterate \n to \001 so that multiline entries fit on a single line. | 553 | # Transliterate \n to SOH so that multiline entries fit on a single line. |
| 509 | # Discard irrelevant rlog output. | 554 | # Discard irrelevant rlog output. |
| 510 | $AWK <$rlogout ' | 555 | $AWK ' |
| 511 | BEGIN { repository = "'"$repository"'" } | 556 | BEGIN { |
| 512 | /^RCS file:/ { | 557 | pository = "'"$pository"'" |
| 513 | if (repository != "") { | 558 | SOH="'"$SOH"'" |
| 514 | filename = $3 | 559 | } |
| 515 | if (substr(filename, 1, length(repository) + 1) == repository "/") { | 560 | /^RCS file: / { |
| 516 | filename = substr(filename, length(repository) + 2) | 561 | if (pository != "") { |
| 562 | filename = substr($0, 11) | ||
| 563 | if (substr(filename, 1, length(pository)) == pository) { | ||
| 564 | filename = substr(filename, length(pository) + 1) | ||
| 517 | } | 565 | } |
| 518 | if (filename ~ /,v$/) { | 566 | if (filename ~ /,v$/) { |
| 519 | filename = substr(filename, 1, length(filename) - 2) | 567 | filename = substr(filename, 1, length(filename) - 2) |
| @@ -526,7 +574,7 @@ $AWK <$rlogout ' | |||
| 526 | } | 574 | } |
| 527 | rev = "?" | 575 | rev = "?" |
| 528 | } | 576 | } |
| 529 | /^Working file:/ { if (repository == "") filename = $3 } | 577 | /^Working file: / { if (repository == "") filename = substr($0, 15) } |
| 530 | /'"$rlog_revision_pattern"'/, /^(-----------*|===========*)$/ { | 578 | /'"$rlog_revision_pattern"'/, /^(-----------*|===========*)$/ { |
| 531 | line = $0 | 579 | line = $0 |
| 532 | if (line ~ /'"$rlog_revision_pattern"'/) { | 580 | if (line ~ /'"$rlog_revision_pattern"'/) { |
| @@ -547,7 +595,7 @@ $AWK <$rlogout ' | |||
| 547 | } | 595 | } |
| 548 | time = substr($3, 1, length($3) - 1) | 596 | time = substr($3, 1, length($3) - 1) |
| 549 | author = substr($5, 1, length($5)-1) | 597 | author = substr($5, 1, length($5)-1) |
| 550 | printf "%s %s %s %s %s %c", filename, rev, date, time, author, 1 | 598 | printf "%s%s%s%s%s%s%s%s%s%s", filename, SOH, rev, SOH, date, SOH, time, SOH, author, SOH |
| 551 | rev = "?" | 599 | rev = "?" |
| 552 | next | 600 | next |
| 553 | } | 601 | } |
| @@ -556,29 +604,25 @@ $AWK <$rlogout ' | |||
| 556 | if (line == "Initial revision" || line ~ /^file .+ was initially added on branch .+\.$/) { | 604 | if (line == "Initial revision" || line ~ /^file .+ was initially added on branch .+\.$/) { |
| 557 | line = "New file." | 605 | line = "New file." |
| 558 | } | 606 | } |
| 559 | printf "%s%c", line, 1 | 607 | printf "%s%s", line, SOH |
| 560 | } | 608 | } |
| 561 | ' | | 609 | ' <"$rlogfile" | |
| 562 | 610 | ||
| 563 | # Now each line is of the form | 611 | # Now each line is of the form |
| 564 | # FILENAME REVISION YYYY-MM-DD HH:MM:SS[+-TIMEZONE] AUTHOR \001LOG | 612 | # FILENAME@REVISION@YYYY-MM-DD@HH:MM:SS[+-TIMEZONE]@AUTHOR@LOG |
| 565 | # where \001 stands for a carriage return, | 613 | # where @ stands for an SOH (octal code 001), |
| 566 | # and each line of the log is terminated by \001 instead of \n. | 614 | # and each line of LOG is terminated by SOH instead of \n. |
| 567 | # Sort the log entries, first by date+time (in reverse order), | 615 | # Sort the log entries, first by date+time (in reverse order), |
| 568 | # then by author, then by log entry, and finally by file name and revision | 616 | # then by author, then by log entry, and finally by file name and revision |
| 569 | # (just in case). | 617 | # (just in case). |
| 570 | sort +2 -4r +4 +0 | | 618 | sort -t"$SOH" +2 -4r +4 +0 | |
| 571 | 619 | ||
| 572 | # Finally, reformat the sorted log entries. | 620 | # Finally, reformat the sorted log entries. |
| 573 | $AWK ' | 621 | $AWK -F"$SOH" ' |
| 574 | BEGIN { | 622 | BEGIN { |
| 575 | logTZ = "'"$logTZ"'" | 623 | logTZ = "'"$logTZ"'" |
| 576 | revision = "'"$revision"'" | 624 | revision = "'"$revision"'" |
| 577 | 625 | ||
| 578 | # Some awk variants do not understand "\001", so we have to | ||
| 579 | # put the char directly in the file. | ||
| 580 | SOH="" # <-- There is a single SOH (octal code 001) here. | ||
| 581 | |||
| 582 | # Initialize the fullname and mailaddr associative arrays. | 626 | # Initialize the fullname and mailaddr associative arrays. |
| 583 | '"$initialize_fullname"' | 627 | '"$initialize_fullname"' |
| 584 | '"$initialize_mailaddr"' | 628 | '"$initialize_mailaddr"' |
| @@ -594,7 +638,8 @@ $AWK ' | |||
| 594 | } | 638 | } |
| 595 | 639 | ||
| 596 | { | 640 | { |
| 597 | newlog = substr($0, 1 + index($0, SOH)) | 641 | newlog = "" |
| 642 | for (i = 6; i < NF; i++) newlog = newlog $i "\n" | ||
| 598 | 643 | ||
| 599 | # Ignore log entries prefixed by "#". | 644 | # Ignore log entries prefixed by "#". |
| 600 | if (newlog ~ /^#/) { next } | 645 | if (newlog ~ /^#/) { next } |