aboutsummaryrefslogtreecommitdiff
path: root/gnu/usr.bin/cvs/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin/cvs/contrib')
-rw-r--r--gnu/usr.bin/cvs/contrib/README68
-rw-r--r--gnu/usr.bin/cvs/contrib/cln_hist.pl91
-rw-r--r--gnu/usr.bin/cvs/contrib/commit_prep.pl168
-rw-r--r--gnu/usr.bin/cvs/contrib/cvs_acls.pl142
-rw-r--r--gnu/usr.bin/cvs/contrib/cvscheck84
-rw-r--r--gnu/usr.bin/cvs/contrib/cvscheck.man53
-rw-r--r--gnu/usr.bin/cvs/contrib/cvshelp.man562
-rw-r--r--gnu/usr.bin/cvs/contrib/descend116
-rw-r--r--gnu/usr.bin/cvs/contrib/descend.man115
-rw-r--r--gnu/usr.bin/cvs/contrib/dirfns481
-rw-r--r--gnu/usr.bin/cvs/contrib/log.pl104
-rw-r--r--gnu/usr.bin/cvs/contrib/log_accum.pl331
-rw-r--r--gnu/usr.bin/cvs/contrib/mfpipe.pl87
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/ChangeLog119
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/INSTALL83
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile78
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/README14
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/compile-all.el52
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/cookie.el884
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll-debug.el298
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll.el386
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/elib-node.el89
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-startup.el6
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.el1476
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.info1367
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.texinfo1437
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/texinfo.tex3230
-rw-r--r--gnu/usr.bin/cvs/contrib/rcs-to-cvs208
-rw-r--r--gnu/usr.bin/cvs/contrib/rcslock.pl234
-rw-r--r--gnu/usr.bin/cvs/contrib/sccs2rcs277
30 files changed, 12640 insertions, 0 deletions
diff --git a/gnu/usr.bin/cvs/contrib/README b/gnu/usr.bin/cvs/contrib/README
new file mode 100644
index 000000000000..412be26745d9
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/README
@@ -0,0 +1,68 @@
+@(#)README 1.8 92/04/10
+
+This "contrib" directory is a place holder for code/scripts sent to
+me by contributors around the world. This READM file will be kept
+up-to-date from release to release. BUT, I must point out that these
+contributions are really, REALLY UNSSUPPORTED. In fact, I probably
+don't even know what they do. Nor do I guarantee to have tried them,
+or ported them to work with this CVS distribution. If you have questions,
+you might contact the author, but you should not necessarily expect
+a reply. USE AT YOUR OWN RISK -- and all that stuff.
+
+Contents of this directory:
+
+ README This file.
+ log.pl A perl script suitable for including in your
+ $CVSROOT/CVSROOT/loginfo file for logging commit
+ changes. Includes the RCS revision of the change
+ as part of the log.
+ Contributed by Kevin Samborn <samborn@sunrise.com>.
+ pcl-cvs A directory that contains GNU Emacs lisp code which
+ implements a CVS-mode for emacs.
+ Contributed by Per Cederqvist <ceder@lysator.liu.se>.
+ commit_prep.pl A perl script, to be combined with log_accum.pl, to
+ log_accum.pl provide for a way to combine the individual log
+ messages of a multi-directory "commit" into a
+ single log message, and mail the result somewhere.
+ Also does other checks for $Id and that you are
+ committing the correct revision of the file.
+ Read the comments carefully.
+ Contributed by David Hampton <hampton@cisco.com>.
+ mfpipe.pl Another perl script for logging. Allows you to
+ pipe the log message to a file and/or send mail
+ to some alias.
+ Contributed by John Clyne <clyne@niwot.scd.ucar.edu>.
+ rcs-to-cvs Script to import sources that may have been under
+ RCS control already.
+ Contributed by Per Cederqvist <ceder@lysator.liu.se>.
+ cvscheck Identifies files added, changed, or removed in a
+ cvscheck.man checked out CVS tree; also notices unknown files.
+ Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
+ cvshelp.man An introductory manual page written by Lowell Skoog
+ <fluke!lowell@uunet.uu.net>. It is most likely
+ out-of-date relative to CVS 1.3, but still may be
+ useful.
+ dirfns A shar file which contains some code that might
+ help your system support opendir/readdir/closedir,
+ if it does not already.
+ Copied from the C-News distribution.
+ rcslock.pl A perl script that can be added to your commitinfo
+ file that tries to determine if your RCS file is
+ currently locked by someone else, as might be the
+ case for a binary file.
+ Contributed by John Rouillard <rouilj@cs.umb.edu>.
+ cvs_acls.pl A perl script that implements Access Control Lists
+ by using the "commitinfo" hook provided with the
+ "cvs commit" command.
+ Contributed by David G. Grubbs <dgg@ksr.com>.
+ descend A shell script that can be used to recursively
+ descend.man descend through a directory. In CVS 1.2, this was
+ very useful, since many of the commands were not
+ recursive. In CVS 1.3 (and later), however, most of
+ the commands are recursive. However, this may still
+ come in handy.
+ Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
+ cln_hist.pl A perl script to compress your
+ $CVSROOT/CVSROOT/history file, as it can grow quite
+ large after extended use.
+ Contributed by David G. Grubbs <dgg@ksr.com>
diff --git a/gnu/usr.bin/cvs/contrib/cln_hist.pl b/gnu/usr.bin/cvs/contrib/cln_hist.pl
new file mode 100644
index 000000000000..b353edc7023e
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/cln_hist.pl
@@ -0,0 +1,91 @@
+#!/usr/bin/perl -- # -*-Perl-*-
+#
+# cln_hist.pl,v 1.1 1992/04/10 03:04:15 berliner Exp
+# Contributed by David G. Grubbs <dgg@ksr.com>
+#
+# Clean up the history file. 10 Record types: MAR OFT WUCG
+#
+# WUCG records are thrown out.
+# MAR records are retained.
+# T records: retain only last tag with same combined tag/module.
+#
+# Two passes: Walk through the first time and remember the
+# 1. Last Tag record with same "tag" and "module" names.
+# 2. Last O record with unique user/module/directory, unless followed
+# by a matching F record.
+#
+
+$r = $ENV{"CVSROOT"};
+$c = "$r/CVSROOT";
+$h = "$c/history";
+
+eval "print STDERR \$die='Unknown parameter $1\n' if !defined \$$1; \$$1=\$';"
+ while ($ARGV[0] =~ /^(\w+)=/ && shift(@ARGV));
+exit 255 if $die; # process any variable=value switches
+
+%tags = ();
+%outs = ();
+
+#
+# Move history file to safe place and re-initialize a new one.
+#
+rename($h, "$h.bak");
+open(XX, ">$h");
+close(XX);
+
+#
+# Pass1 -- remember last tag and checkout.
+#
+open(HIST, "$h.bak");
+while (<HIST>) {
+ next if /^[MARWUCG]/;
+
+ # Save whole line keyed by tag|module
+ if (/^T/) {
+ @tmp = split(/\|/, $_);
+ $tags{$tmp[4] . '|' . $tmp[5]} = $_;
+ }
+ # Save whole line
+ if (/^[OF]/) {
+ @tmp = split(/\|/, $_);
+ $outs{$tmp[1] . '|' . $tmp[2] . '|' . $tmp[5]} = $_;
+ }
+}
+
+#
+# Pass2 -- print out what we want to save.
+#
+open(SAVE, ">$h.work");
+open(HIST, "$h.bak");
+while (<HIST>) {
+ next if /^[FWUCG]/;
+
+ # If whole line matches saved (i.e. "last") one, print it.
+ if (/^T/) {
+ @tmp = split(/\|/, $_);
+ next if $tags{$tmp[4] . '|' . $tmp[5]} ne $_;
+ }
+ # Save whole line
+ if (/^O/) {
+ @tmp = split(/\|/, $_);
+ next if $outs{$tmp[1] . '|' . $tmp[2] . '|' . $tmp[5]} ne $_;
+ }
+
+ print SAVE $_;
+}
+
+#
+# Put back the saved stuff
+#
+system "cat $h >> $h.work";
+
+if (-s $h) {
+ rename ($h, "$h.interim");
+ print "history.interim has non-zero size.\n";
+} else {
+ unlink($h);
+}
+
+rename ("$h.work", $h);
+
+exit(0);
diff --git a/gnu/usr.bin/cvs/contrib/commit_prep.pl b/gnu/usr.bin/cvs/contrib/commit_prep.pl
new file mode 100644
index 000000000000..b3f7e9aa9f96
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/commit_prep.pl
@@ -0,0 +1,168 @@
+#!/usr/local/bin/perl -w
+#
+#
+# Perl filter to handle pre-commit checking of files. This program
+# records the last directory where commits will be taking place for
+# use by the log_accumulate script. For new file, it forcing the
+# existence of a RCS "Id" keyword in the first ten lines of the file.
+# For existing files, it checks version number in the "Id" line to
+# prevent losing changes because an old version of a file was copied
+# into the direcory.
+#
+# Possible future enhancements:
+#
+#
+# Check for cruft left by unresolved conflicts. Search for
+# "^<<<<<<<$", "^-------$", and "^>>>>>>>$".
+#
+# Look for a copyright and automagically update it to the
+# current year.
+#
+# Contributed by David Hampton <hampton@cisco.com>
+#
+
+############################################################
+#
+# Configurable options
+#
+############################################################
+#
+# Check each file (except dot files) for an RCS "Id" keyword.
+#
+$check_id = 1;
+
+#
+# Record the directory for later use by the log_accumulate stript.
+#
+$record_directory = 1;
+
+############################################################
+#
+# Constants
+#
+############################################################
+$LAST_FILE = "/tmp/#cvs.lastdir";
+$ENTRIES = "CVS/Entries";
+
+$NoId = "
+%s - Does not contain a line with the keyword \"Id:\".
+ Please see the template files for an example.\n";
+
+# Protect string from substitution by RCS.
+$NoName = "
+%s - The ID line should contain only \"\$\I\d\:\ \$\" for a newly created file.\n";
+
+$BadName = "
+%s - The file name '%s' in the ID line does not match
+ the actual filename.\n";
+
+$BadVersion = "
+%s - How dare you!! You replaced your copy of the file '%s',
+ which was based upon version %s, with an %s version based
+ upon %s. Please move your '%s' out of the way, perform an
+ update to get the current version, and them merge your changes
+ into that file.\n";
+
+############################################################
+#
+# Subroutines
+#
+############################################################
+
+sub write_line {
+ local($filename, $line) = @_;
+ open(FILE, ">$filename") || die("Cannot open $filename, stopped");
+ print(FILE $line, "\n");
+ close(FILE);
+}
+
+sub check_version {
+ local($i, $id, $rname, $version);
+ local($filename, $cvsversion) = @_;
+
+ open(FILE, $filename) || die("Cannot open $filename, stopped");
+ for ($i = 1; $i < 10; $i++) {
+ $pos = -1;
+ last if eof(FILE);
+ $line = <FILE>;
+ $pos = index($line, "Id: ");
+ last if ($pos >= 0);
+ }
+
+ if ($pos == -1) {
+ printf($NoId, $filename);
+ return(1);
+ }
+
+ ($id, $rname, $version) = split(' ', substr($line, $pos));
+ if ($cvsversion{$filename} == 0) {
+ if ($rname ne "\$") {
+ printf($NoName, $filename);
+ return(1);
+ }
+ return(0);
+ }
+
+ if ($rname ne "$filename,v") {
+ printf($BadName, $filename, substr($rname, 0, length($rname)-2));
+ return(1);
+ }
+ if ($cvsversion{$filename} < $version) {
+ printf($BadVersion, $filename, $filename, $cvsversion{$filename},
+ "newer", $version, $filename);
+ return(1);
+ }
+ if ($cvsversion{$filename} > $version) {
+ printf($BadVersion, $filename, $filename, $cvsversion{$filename},
+ "older", $version, $filename);
+ return(1);
+ }
+ return(0);
+}
+
+#############################################################
+#
+# Main Body
+#
+############################################################
+
+$id = getpgrp();
+#print("ARGV - ", join(":", @ARGV), "\n");
+#print("id - ", id, "\n");
+
+#
+# Suck in the Entries file
+#
+open(ENTRIES, $ENTRIES) || die("Cannot open $ENTRIES.\n");
+while (<ENTRIES>) {
+ local($filename, $version) = split('/', substr($_, 1));
+ $cvsversion{$filename} = $version;
+}
+
+#
+# Now check each file name passed in, except for dot files. Dot files
+# are considered to be administrative files by this script.
+#
+if ($check_id != 0) {
+ $failed = 0;
+ $directory = $ARGV[0];
+ shift @ARGV;
+ foreach $arg (@ARGV) {
+ next if (index($arg, ".") == 0);
+ $failed += &check_version($arg);
+ }
+ if ($failed) {
+ print "\n";
+ exit(1);
+ }
+}
+
+#
+# Record this directory as the last one checked. This will be used
+# by the log_accumulate script to determine when it is processing
+# the final directory of a multi-directory commit.
+#
+if ($record_directory != 0) {
+ &write_line("$LAST_FILE.$id", $directory);
+}
+exit(0);
diff --git a/gnu/usr.bin/cvs/contrib/cvs_acls.pl b/gnu/usr.bin/cvs/contrib/cvs_acls.pl
new file mode 100644
index 000000000000..1a0096a3a356
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/cvs_acls.pl
@@ -0,0 +1,142 @@
+#!/usr/bin/perl -- # -*-Perl-*-
+#
+# cvs_acls.pl,v 1.2 1992/04/11 16:01:24 berliner Exp
+#
+# Access control lists for CVS. dgg@ksr.com (David G. Grubbs)
+#
+# CVS "commitinfo" for matching repository names, running the program it finds
+# on the same line. More information is available in the CVS man pages.
+#
+# ==== INSTALLATION:
+#
+# To use this program as I intended, do the following four things:
+#
+# 0. Install PERL. :-)
+#
+# 1. Put one line, as the *only* non-comment line, in your commitinfo file:
+#
+# DEFAULT /usr/local/bin/cvs_acls
+#
+# 2. Install this file as /usr/local/bin/cvs_acls and make it executable.
+#
+# 3. Create a file named $CVSROOT/CVSROOT/avail.
+#
+# ==== FORMAT OF THE avail FILE:
+#
+# The avail file determines whether you may commit files. It contains lines
+# read from top to bottom, keeping track of a single "bit". The "bit"
+# defaults to "on". It can be turned "off" by "unavail" lines and "on" by
+# "avail" lines. ==> Last one counts.
+#
+# Any line not beginning with "avail" or "unavail" is ignored.
+#
+# Lines beginning with "avail" or "unavail" are assumed to be '|'-separated
+# triples: (All spaces and tabs are ignored in a line.)
+#
+# {avail.*,unavail.*} [| user,user,... [| repos,repos,...]]
+#
+# 1. String starting with "avail" or "unavail".
+# 2. Optional, comma-separated list of usernames.
+# 3. Optional, comma-separated list of repository pathnames.
+# These are pathnames relative to $CVSROOT. They can be directories or
+# filenames. A directory name allows access to all files and
+# directories below it.
+#
+# Example: (Text from the ';;' rightward may not appear in the file.)
+#
+# unavail ;; Make whole repository unavailable.
+# avail|dgg ;; Except for user "dgg".
+# avail|fred, john|bin/ls ;; Except when "fred" or "john" commit to
+# ;; the module whose repository is "bin/ls"
+#
+# PROGRAM LOGIC:
+#
+# CVS passes to @ARGV an absolute directory pathname (the repository
+# appended to your $CVSROOT variable), followed by a list of filenames
+# within that directory.
+#
+# We walk through the avail file looking for a line that matches both
+# the username and repository.
+#
+# A username match is simply the user's name appearing in the second
+# column of the avail line in a space-or-comma separate list.
+#
+# A repository match is either:
+# - One element of the third column matches $ARGV[0], or some
+# parent directory of $ARGV[0].
+# - Otherwise *all* file arguments ($ARGV[1..$#ARGV]) must be
+# in the file list in one avail line.
+# - In other words, using directory names in the third column of
+# the avail file allows committing of any file (or group of
+# files in a single commit) in the tree below that directory.
+# - If individual file names are used in the third column of
+# the avail file, then files must be committed individually or
+# all files specified in a single commit must all appear in
+# third column of a single avail line.
+#
+
+$debug = 0;
+$cvsroot = $ENV{'CVSROOT'};
+$availfile = $cvsroot . "/CVSROOT/avail";
+$myname = $ENV{"USER"} if !($myname = $ENV{"LOGNAME"});
+
+eval "print STDERR \$die='Unknown parameter $1\n' if !defined \$$1; \$$1=\$';"
+ while ($ARGV[0] =~ /^(\w+)=/ && shift(@ARGV));
+exit 255 if $die; # process any variable=value switches
+
+die "Must set CVSROOT\n" if !$cvsroot;
+($repos = shift) =~ s:^$cvsroot/::;
+grep($_ = $repos . '/' . $_, @ARGV);
+
+print "$$ Repos: $repos\n","$$ ==== ",join("\n$$ ==== ",@ARGV),"\n" if $debug;
+
+$exit_val = 0; # Good Exit value
+
+$universal_off = 0;
+open (AVAIL, $availfile) || exit(0); # It is ok for avail file not to exist
+while (<AVAIL>) {
+ chop;
+ next if /^\s*\#/;
+ next if /^\s*$/;
+ ($flagstr, $u, $m) = split(/[\s,]*\|[\s,]*/, $_);
+
+ # Skip anything not starting with "avail" or "unavail" and complain.
+ (print "Bad avail line: $_\n"), next
+ if ($flagstr !~ /^avail/ && $flagstr !~ /^unavail/);
+
+ # Set which bit we are playing with. ('0' is OK == Available).
+ $flag = (($& eq "avail") ? 0 : 1);
+
+ # If we find a "universal off" flag (i.e. a simple "unavail") remember it
+ $universal_off = 1 if ($flag && !$u && !$m);
+
+ # $myname considered "in user list" if actually in list or is NULL
+ $in_user = (!$u || grep ($_ eq $myname, split(/[\s,]+/,$u)));
+ print "$$ \$myname($myname) in user list: $_\n" if $debug && $in_user;
+
+ # Module matches if it is a NULL module list in the avail line. If module
+ # list is not null, we check every argument combination.
+ if (!($in_repo = !$m)) {
+ @tmp = split(/[\s,]+/,$m);
+ for $j (@tmp) {
+ # If the repos from avail is a parent(or equal) dir of $repos, OK
+ $in_repo = 1, last if ($repos eq $j || $repos =~ /^$j\//);
+ }
+ if (!$in_repo) {
+ $in_repo = 1;
+ for $j (@ARGV) {
+ last if !($in_repo = grep ($_ eq $j, @tmp));
+ }
+ }
+ }
+ print "$$ \$repos($repos) in repository list: $_\n" if $debug && $in_repo;
+
+ $exit_val = $flag if ($in_user && $in_repo);
+ print "$$ ==== \$exit_val = $exit_val\n$$ ==== \$flag = $flag\n" if $debug;
+}
+close(AVAIL);
+print "$$ ==== \$exit_val = $exit_val\n" if $debug;
+print "**** Access denied: Insufficient Karma ($myname|$repos)\n" if $exit_val;
+print "**** Access allowed: Personal Karma exceeds Environmental Karma.\n"
+ if $universal_off && !$exit_val;
+exit($exit_val);
diff --git a/gnu/usr.bin/cvs/contrib/cvscheck b/gnu/usr.bin/cvs/contrib/cvscheck
new file mode 100644
index 000000000000..67fdbbde10d0
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/cvscheck
@@ -0,0 +1,84 @@
+#! /bin/sh
+# cvscheck,v 1.2 1992/04/10 03:04:19 berliner Exp
+#
+# cvscheck - identify files added, changed, or removed
+# in CVS working directory
+#
+# Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
+#
+# This program should be run in a working directory that has been
+# checked out using CVS. It identifies files that have been added,
+# changed, or removed in the working directory, but not "cvs
+# committed". It also determines whether the files have been "cvs
+# added" or "cvs removed". For directories, it is only practical to
+# determine whether they have been added.
+
+name=cvscheck
+changes=0
+
+# If we can't run CVS commands in this directory
+cvs status . > /dev/null 2>&1
+if [ $? != 0 ] ; then
+
+ # Bail out
+ echo "$name: there is no version here; bailing out" 1>&2
+ exit 1
+fi
+
+# Identify files added to working directory
+for file in .* * ; do
+
+ # Skip '.' and '..'
+ if [ $file = '.' -o $file = '..' ] ; then
+ continue
+ fi
+
+ # If a regular file
+ if [ -f $file ] ; then
+ if cvs status $file | grep -s '^From:[ ]*New file' ; then
+ echo "file added: $file - not CVS committed"
+ changes=`expr $changes + 1`
+ elif cvs status $file | grep -s '^From:[ ]*no entry for' ; then
+ echo "file added: $file - not CVS added, not CVS committed"
+ changes=`expr $changes + 1`
+ fi
+
+ # Else if a directory
+ elif [ -d $file -a $file != CVS.adm ] ; then
+
+ # Move into it
+ cd $file
+
+ # If CVS commands don't work inside
+ cvs status . > /dev/null 2>&1
+ if [ $? != 0 ] ; then
+ echo "directory added: $file - not CVS added"
+ changes=`expr $changes + 1`
+ fi
+
+ # Move back up
+ cd ..
+ fi
+done
+
+# Identify changed files
+changedfiles=`cvs diff | egrep '^diff' | awk '{print $3}'`
+for file in $changedfiles ; do
+ echo "file changed: $file - not CVS committed"
+ changes=`expr $changes + 1`
+done
+
+# Identify files removed from working directory
+removedfiles=`cvs status | egrep '^File:[ ]*no file' | awk '{print $4}'`
+
+# Determine whether each file has been cvs removed
+for file in $removedfiles ; do
+ if cvs status $file | grep -s '^From:[ ]*-' ; then
+ echo "file removed: $file - not CVS committed"
+ else
+ echo "file removed: $file - not CVS removed, not CVS committed"
+ fi
+ changes=`expr $changes + 1`
+done
+
+exit $changes
diff --git a/gnu/usr.bin/cvs/contrib/cvscheck.man b/gnu/usr.bin/cvs/contrib/cvscheck.man
new file mode 100644
index 000000000000..10d47f5115fb
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/cvscheck.man
@@ -0,0 +1,53 @@
+.\" cvscheck.man,v 1.1 1992/04/10 03:04:20 berliner Exp
+.\" Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
+.TH CVSCHECK LOCAL "4 March 1991" FLUKE
+.SH NAME
+cvscheck \- identify files added, changed, or removed in a CVS working
+directory
+.SH SYNOPSIS
+.B cvscheck
+.SH DESCRIPTION
+This command is a housekeeping aid. It should be run in a working
+directory that has been checked out using CVS. It identifies files
+that have been added, changed, or removed in the working directory, but
+not CVS
+.BR commit ted.
+It also determines whether the files have been CVS
+.BR add ed
+or CVS
+.BR remove d.
+For directories, this command determines only whether they have been
+.BR add ed.
+It operates in the current directory only.
+.LP
+This command provides information that is available using CVS
+.B status
+and CVS
+.BR diff .
+The advantage of
+.B cvscheck
+is that its output is very concise. It saves you the strain (and
+potential error) of interpreting the output of CVS
+.B status
+and
+.BR diff .
+.LP
+See
+.BR cvs (local)
+or
+.BR cvshelp (local)
+for instructions on how to add or remove a file or directory in a
+CVS-controlled package.
+.SH DIAGNOSTICS
+The exit status is 0 if no files have been added, changed, or removed
+from the current directory. Otherwise, the command returns a count of
+the adds, changes, and deletes.
+.SH SEE ALSO
+.BR cvs (local),
+.BR cvshelp (local)
+.SH AUTHOR
+Lowell Skoog
+.br
+Software Technology Group
+.br
+Technical Computing
diff --git a/gnu/usr.bin/cvs/contrib/cvshelp.man b/gnu/usr.bin/cvs/contrib/cvshelp.man
new file mode 100644
index 000000000000..a7128a8ca83c
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/cvshelp.man
@@ -0,0 +1,562 @@
+.\" cvshelp.man,v 1.1 1992/04/10 03:04:21 berliner Exp
+.\" Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
+.\" Full space in nroff; half space in troff
+.de SP
+.if n .sp
+.if t .sp .5
+..
+.\" Start a command example
+.de XS
+.SP
+.in +.5i
+.ft B
+.nf
+..
+.\" End a command example
+.de XE
+.fi
+.ft P
+.in -.5i
+.SP
+..
+.TH CVSHELP LOCAL "17 March 1991" FLUKE
+.SH NAME
+cvshelp \- advice on using the Concurrent Versions System
+.SH DESCRIPTION
+This man page is based on experience using CVS.
+It is bound to change as we gain more experience.
+If you come up with better advice than is found here,
+contact the Software Technology
+Group and we will add it to this page.
+.SS "Getting Started"
+Use the following steps to prepare to use CVS:
+.TP
+\(bu
+Take a look at the CVS manual page to see what it can do for you, and
+if it fits your environment (or can possibly be made to fit your
+environment).
+.XS
+man cvs
+.XE
+If things look good, continue on...
+.TP
+\(bu
+Setup the master source repository. Choose a directory with
+ample disk space available for source files. This is where the RCS
+`,v' files will be stored. Say you choose
+.B /src/master
+as the root
+of your source repository. Make the
+.SB CVSROOT.adm
+directory in the root of the source repository:
+.XS
+mkdir /src/master/CVSROOT.adm
+.XE
+.TP
+\(bu
+Populate this directory with the
+.I loginfo
+and
+.I modules
+files from the
+.B "/usr/doc/local/cvs"
+directory. Edit these files to reflect your local source repository
+environment \- they may be quite small initially, but will grow as
+sources are added to your source repository. Turn these files into
+RCS controlled files:
+.XS
+cd /src/master/CVSROOT.adm
+ci \-m'Initial loginfo file' loginfo
+ci \-m'Initial modules file' modules
+.XE
+.TP
+\(bu
+Run the command:
+.XS
+mkmodules /src/master/CVSROOT.adm
+.XE
+This will build the
+.BR ndbm (3)
+file for the modules database.
+.TP
+\(bu
+Remember to edit the
+.I modules
+file manually when sources are checked
+in with
+.B checkin
+or CVS
+.BR add .
+A copy of the
+.I modules
+file for editing can be retrieved with the command:
+.XS
+cvs checkout CVSROOT.adm
+.XE
+.TP
+\(bu
+Have all users of the CVS system set the
+.SM CVSROOT
+environment variable appropriately to reflect the placement of your
+source repository. If the above example is used, the following
+commands can be placed in a
+.I .login
+or
+.I .profile
+file:
+.XS
+setenv CVSROOT /src/master
+.XE
+for csh users, and
+.XS
+CVSROOT=/src/master; export CVSROOT
+.XE
+for sh users.
+.SS "Placing Locally Written Sources Under CVS Control"
+Say you want to place the `whizbang' sources under
+CVS control. Say further that the sources have never
+been under revision control before.
+.TP
+\(bu
+Move the source hierarchy (lock, stock, and barrel)
+into the master source repository:
+.XS
+mv ~/whizbang $CVSROOT
+.XE
+.TP
+\(bu
+Clean out unwanted object files:
+.XS
+cd $CVSROOT/whizbang
+make clean
+.XE
+.TP
+\(bu
+Turn every file in the hierarchy into an RCS controlled file:
+.XS
+descend \-f 'ci \-t/dev/null \-m"Placed under CVS control" \-nV\fR\fIx\fR\fB_\fR\fIy\fR\fB *'
+.XE
+In this example, the initial release tag is \fBV\fIx\fB_\fIy\fR,
+representing version \fIx\fR.\fIy\fR.
+.LP
+You can use CVS on sources that are already under RCS control.
+The following example shows how.
+In this example, the source package is called `skunkworks'.
+.TP
+\(bu
+Move the source hierarchy into the master source
+repository:
+.XS
+mv ~/skunkworks $CVSROOT
+.XE
+.TP
+\(bu
+Clean out unwanted object files:
+.XS
+cd $CVSROOT/skunkworks
+make clean
+.XE
+.TP
+\(bu
+Clean out unwanted working files, leaving only the RCS `,v' files:
+.XS
+descend \-r rcsclean
+.XE
+Note: If any working files have been checked out and changed,
+.B rcsclean
+will fail. Check in the modified working files
+and run the command again.
+.TP
+\(bu
+Get rid of
+.SB RCS
+subdirectories. CVS does not use them.
+.XS
+descend \-r \-f 'mv RCS/*,v .'
+descend \-r \-f 'rmdir RCS'
+.XE
+.TP
+\(bu
+Delete any unwanted files that remain in the source hierarchy. Then
+make sure all files are under RCS control:
+.XS
+descend \-f 'ci \-t/dev/null \-m"Placed under CVS control" \-n\fR\fItag\fR\fB *'
+.XE
+.I tag
+is the latest symbolic revision tag that you applied to your package
+(if any). Note: This command will probably generate lots of error
+messages (for directories and existing RCS files) that you can
+ignore.
+.SS "Placing a Third-Party Source Distribution Under CVS Control"
+The
+.B checkin
+command checks third-party sources into CVS. The
+difference between third-party sources and locally
+written sources is that third-party sources must be checked into a
+separate branch (called the
+.IR "vendor branch" )
+of the RCS tree. This makes it possible to merge local changes to
+the sources with later releases from the vendor.
+.TP
+\(bu
+Save the original distribution kit somewhere. For example, if the
+master source repository is
+.B /src/master
+the distribution kit could be saved in
+.BR /src/dist .
+Organize the distribution directory so that each release
+is clearly identifiable.
+.TP
+\(bu
+Unpack the package in a scratch directory, for example
+.BR ~/scratch .
+.TP
+\(bu
+Create a repository for the package.
+In this example, the package is called `Bugs-R-Us 4.3'.
+.XS
+mkdir $CVSROOT/bugs
+.XE
+.TP
+\(bu
+Check in the unpacked files:
+.XS
+cd ~/scratch
+checkin \-m 'Bugs-R-Us 4.3 distribution' bugs VENDOR V4_3
+.XE
+There is nothing magic about the tag `VENDOR', which is applied to
+the vendor branch. You can use whatever tag you want. `VENDOR' is a
+useful convention.
+.TP
+\(bu
+Never modify vendor files before checking them in.
+Check in the files
+.I exactly
+as you unpacked them.
+If you check in locally modified files, future vendor releases may
+wipe out your local changes.
+.SS "Working With CVS-Controlled Sources"
+To use or edit the sources, you must check out a private copy.
+For the following examples, the master files are assumed to reside in
+.BR "$CVSROOT/behemoth" .
+The working directory is
+.BR "~/work" .
+See
+.BR cvs (local)
+for more details on the commands mentioned below.
+.TP
+.I "To Check Out Working Files
+Use CVS
+.BR checkout :
+.XS
+cd ~/work
+cvs checkout behemoth
+.XE
+There is nothing magic about the working directory. CVS will check
+out sources anywhere you like. Once you have a working copy of the
+sources, you can compile or edit them as desired.
+.TP
+.I "To Display Changes You Have Made"
+Use CVS
+.BR diff
+to display detailed changes, equivalent to
+.BR rcsdiff (local).
+You can also use
+.BR cvscheck (local)
+to list files added, changed, and removed in
+the directory, but not yet
+.BR commit ted.
+You must be in a directory containing working files.
+.TP
+.I "To Display Revision Information"
+Use CVS
+.BR log ,
+which is equivalent to
+.BR rlog (local).
+You must be in a directory containing working files.
+.TP
+.I "To Update Working Files"
+Use CVS
+.BR update
+in a directory containing working files.
+This command brings your working files up
+to date with changes checked into the
+master repository since you last checked out or updated
+your files.
+.TP
+.I "To Check In Your Changes"
+Use CVS
+.BR commit
+in a directory containing working files.
+This command checks your changes into the master repository.
+You can specify files by name or use
+.XS
+cvs commit \-a
+.XE
+to
+.B commit
+all the files you have changed.
+.TP
+.I "To Add a File"
+Add the file to the working directory.
+Use CVS
+.B add
+to mark the file as added.
+Use CVS
+.B commit
+to add the file to the master repository.
+.TP
+.I "To Remove a File"
+Remove the file from the working directory.
+Use CVS
+.B remove
+to mark the file as removed.
+Use CVS
+.B commit
+to move the file from its current location in the master repository
+to the CVS
+.IR Attic
+directory.
+.TP
+.I "To Add a Directory"
+Add the directory to the working directory.
+Use CVS
+.B add
+to add the directory to the master repository.
+.TP
+.I "To Remove a Directory"
+.br
+You shouldn't remove directories under CVS. You should instead remove
+their contents and then prune them (using the
+.B \-f
+and
+.B \-p
+options) when you
+.B checkout
+or
+.B update
+your working files.
+.TP
+.I "To Tag a Release"
+Use CVS
+.B tag
+to apply a symbolic tag to the latest revision of each file in the
+master repository. For example:
+.XS
+cvs tag V2_1 behemoth
+.XE
+.TP
+.I "To Retrieve an Exact Copy of a Previous Release"
+During a CVS
+.B checkout
+or
+.BR update ,
+use the
+.B \-r
+option to retrieve revisions associated with a symbolic tag.
+Use the
+.B \-f
+option to ignore all RCS files that do not contain the
+tag.
+Use the
+.B \-p
+option to prune directories that wind up empty because none
+of their files matched the tag. Example:
+.XS
+cd ~/work
+cvs checkout \-r V2_1 \-f \-p behemoth
+.XE
+.SS "Logging Changes"
+It is a good idea to keep a change log together with the
+sources. As a minimum, the change log should name and describe each
+tagged release. The change log should also be under CVS control and
+should be tagged along with the sources.
+.LP
+.BR cvslog (local)
+can help. This command logs
+changes reported during CVS
+.B commit
+operations. It automatically
+updates a change log file in your working directory. When you are
+finished making changes, you (optionally) edit the change log file and
+then commit it to the master repository.
+.LP
+Note: You must edit the change log to describe a new release
+and
+.B commit
+it to the master repository
+.I before
+.BR tag ging
+the release using CVS. Otherwise, the release description will not be
+included in the tagged package.
+.LP
+See
+.BR cvslog (local)
+for more information.
+.SS "Merging a Subsequent Third-Party Distribution"
+The initial steps in this process are identical to placing a
+third-party distribution under CVS for the first time: save the
+distribution kit and unpack the package in a scratch directory. From
+that point the steps diverge.
+The following example considers release 5.0 of the
+Bugs-R-Us package.
+.TP
+\(bu
+Check in the sources after unpacking them:
+.XS
+cd ~/scratch
+checkin \-m 'Bugs-R-Us 5.0 distribution' bugs VENDOR V5_0 \\
+ | tee ~/WARNINGS
+.XE
+It is important to save the output of
+.B checkin
+in a file
+because it lists the sources that have been locally modified.
+It is best to save the file in a different directory (for example,
+your home directory). Otherwise,
+.B checkin
+will try to check it into the master repository.
+.TP
+\(bu
+In your usual working directory, check out a fresh copy of the
+distribution that you just checked in.
+.XS
+cd ~/work
+cvs checkout \-r VENDOR bugs
+.XE
+The
+.B checkout
+command shown above retrieves the latest revision on the vendor branch.
+.TP
+\(bu
+See the `WARNINGS' file for a list of all locally modified
+sources.
+For each locally modified source,
+look at the differences between
+the new distribution and the latest local revision:
+.XS
+cvs diff \-r \fR\fILocalRev file\fR\fB
+.XE
+In this command,
+.I LocalRev
+is the latest
+numeric or symbolic revision
+on the RCS trunk of
+.IR file .
+You can use CVS
+.B log
+to get the revision history.
+.TP
+\(bu
+If your local modifications to a file have been incorporated into
+the vendor's distribution, then you should reset the default RCS
+branch for that file to the vendor branch. CVS doesn't provide a
+mechanism to do this. You have to do it by hand in the master
+repository:
+.XS
+rcs \-bVENDOR \fR\fIfile\fR\fB,v
+.XE
+.TP
+\(bu
+If your local modifications need to be merged with the
+new distribution, use CVS
+.B join
+to do it:
+.XS
+cvs join \-r VENDOR \fR\fIfile\fR\fB
+.XE
+The resulting file will be placed in your working directory.
+Edit it to resolve any overlaps.
+.TP
+\(bu
+Test the merged package.
+.TP
+\(bu
+Commit all modified files to the repository:
+.XS
+cvs commit \-a
+.XE
+.TP
+\(bu
+Tag the repository with a new local tag.
+.SS "Applying Patches to Third-Party Sources"
+Patches are handled in a manner very similar to complete
+third-party distributions. This example considers patches applied to
+Bugs-R-Us release 5.0.
+.TP
+\(bu
+Save the patch files together with the distribution kit
+to which they apply.
+The patch file names should clearly indicate the patch
+level.
+.TP
+\(bu
+In a scratch directory, check out the last `clean' vendor copy \- the
+highest revision on the vendor branch with
+.IR "no local changes" :
+.XS
+cd ~/scratch
+cvs checkout \-r VENDOR bugs
+.XE
+.TP
+\(bu
+Use
+.BR patch (local)
+to apply the patches. You should now have an image of the
+vendor's software just as though you had received a complete,
+new release.
+.TP
+\(bu
+Proceed with the steps described for merging a subsequent third-party
+distribution.
+.TP
+\(bu
+Note: When you get to the step that requires you
+to check out the new distribution after you have
+checked it into the vendor branch, you should move to a different
+directory. Do not attempt to
+.B checkout
+files in the directory in
+which you applied the patches. If you do, CVS will try to merge the
+changes that you made during patching with the version being checked
+out and things will get very confusing. Instead,
+go to a different directory (like your working directory) and
+check out the files there.
+.SS "Advice to Third-Party Source Hackers"
+As you can see from the preceding sections, merging local changes
+into third-party distributions remains difficult, and probably
+always will. This fact suggests some guidelines:
+.TP
+\(bu
+Minimize local changes.
+.I Never
+make stylistic changes.
+Change makefiles only as much as needed for installation. Avoid
+overhauling anything. Pray that the vendor does the same.
+.TP
+\(bu
+Avoid renaming files or moving them around.
+.TP
+\(bu
+Put independent, locally written files like help documents, local
+tools, or man pages in a sub-directory called `local-additions'.
+Locally written files that are linked into an existing executable
+should be added right in with the vendor's sources (not in a
+`local-additions' directory).
+If, in the future,
+the vendor distributes something
+equivalent to your locally written files
+you can CVS
+.B remove
+the files from the `local-additions' directory at that time.
+.SH SEE ALSO
+.BR cvs (local),
+.BR checkin (local),
+.BR cvslog (local),
+.BR cvscheck (local)
+.SH AUTHOR
+Lowell Skoog
+.br
+Software Technology Group
+.br
+Technical Computing
diff --git a/gnu/usr.bin/cvs/contrib/descend b/gnu/usr.bin/cvs/contrib/descend
new file mode 100644
index 000000000000..b63e4a77b3fd
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/descend
@@ -0,0 +1,116 @@
+#! /bin/sh
+# descend,v 1.1 1992/04/03 05:22:52 berliner Exp
+#
+# descend - walk down a directory tree and execute a command at each node
+
+fullname=$0
+name=descend
+usage="Usage: $name [-afqrv] command [directory ...]\n
+\040\040-a\040\040All: descend into directories starting with '.'\n
+\040\040-f\040\040Force: ignore errors during descent\n
+\040\040-q\040\040Quiet: don't print directory names\n
+\040\040-r\040\040Restricted: don't descend into RCS, CVS.adm, SCCS directories\n
+\040\040-v\040\040Verbose: print command before executing it"
+
+# Scan for options
+while getopts afqrv option; do
+ case $option in
+ a)
+ alldirs=$option
+ options=$options" "-$option
+ ;;
+ f)
+ force=$option
+ options=$options" "-$option
+ ;;
+ q)
+ verbose=
+ quiet=$option
+ options=$options" "-$option
+ ;;
+ r)
+ restricted=$option
+ options=$options" "-$option
+ ;;
+ v)
+ verbose=$option
+ quiet=
+ options=$options" "-$option
+ ;;
+ \?)
+ /usr/5bin/echo $usage 1>&2
+ exit 1
+ ;;
+ esac
+done
+shift `expr $OPTIND - 1`
+
+# Get command to execute
+if [ $# -lt 1 ] ; then
+ /usr/5bin/echo $usage 1>&2
+ exit 1
+else
+ command=$1
+ shift
+fi
+
+# If no directory specified, use '.'
+if [ $# -lt 1 ] ; then
+ default_dir=.
+fi
+
+# For each directory specified
+for dir in $default_dir "$@" ; do
+
+ # Spawn sub-shell so we return to starting directory afterward
+ (cd $dir
+
+ # Execute specified command
+ if [ -z "$quiet" ] ; then
+ echo In directory `hostname`:`pwd`
+ fi
+ if [ -n "$verbose" ] ; then
+ echo $command
+ fi
+ eval "$command" || if [ -z "$force" ] ; then exit 1; fi
+
+ # Collect dot file names if necessary
+ if [ -n "$alldirs" ] ; then
+ dotfiles=.*
+ else
+ dotfiles=
+ fi
+
+ # For each file in current directory
+ for file in $dotfiles * ; do
+
+ # Skip '.' and '..'
+ if [ "$file" = "." -o "$file" = ".." ] ; then
+ continue
+ fi
+
+ # If a directory but not a symbolic link
+ if [ -d "$file" -a ! -h "$file" ] ; then
+
+ # If not skipping this type of directory
+ if [ \( "$file" != "RCS" -a \
+ "$file" != "SCCS" -a \
+ "$file" != "CVS" -a \
+ "$file" != "CVS.adm" \) \
+ -o -z "$restricted" ] ; then
+
+ # Recursively descend into it
+ $fullname $options "$command" "$file" \
+ || if [ -z "$force" ] ; then exit 1; fi
+ fi
+
+ # Else if a directory AND a symbolic link
+ elif [ -d "$file" -a -h "$file" ] ; then
+
+ if [ -z "$quiet" ] ; then
+ echo In directory `hostname`:`pwd`/$file: symbolic link: skipping
+ fi
+ fi
+ done
+ ) || if [ -z "$force" ] ; then exit 1; fi
+done
diff --git a/gnu/usr.bin/cvs/contrib/descend.man b/gnu/usr.bin/cvs/contrib/descend.man
new file mode 100644
index 000000000000..adeab3bd3820
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/descend.man
@@ -0,0 +1,115 @@
+.\" descend.man,v 1.1 1992/04/03 05:22:53 berliner Exp
+.TH DESCEND 1 "31 March 1992"
+.SH NAME
+descend \- walk directory tree and execute a command at each node
+.SH SYNOPSIS
+.B descend
+[
+.B \-afqrv
+]
+.I command
+[
+.I directory
+\&.\|.\|.
+]
+.SH DESCRIPTION
+.B descend
+walks down a directory tree and executes a command at each node. It
+is not as versatile as
+.BR find (1),
+but it has a simpler syntax. If no
+.I directory
+is specified,
+.B descend
+starts at the current one.
+.LP
+Unlike
+.BR find ,
+.B descend
+can be told to skip the special directories associated with RCS,
+CVS, and SCCS. This makes
+.B descend
+especially handy for use with these packages. It can be used with
+other commands too, of course.
+.LP
+.B descend
+is a poor man's way to make any command recursive. Note:
+.B descend
+does not follow symbolic links to directories unless they are
+specified on the command line.
+.SH OPTIONS
+.TP 15
+.B \-a
+.I All.
+Descend into directories that begin with '.'.
+.TP
+.B \-f
+.I Force.
+Ignore errors during descent. Normally,
+.B descend
+quits when an error occurs.
+.TP
+.B \-q
+.I Quiet.
+Suppress the message `In directory
+.IR directory '
+that is normally printed during the descent.
+.TP
+.B \-r
+.I Restricted.
+Don't descend into the special directories
+.SB RCS,
+.SB CVS,
+.SB CVS.adm,
+and
+.SB SCCS.
+.TP
+.B \-v
+.I Verbose.
+Print
+.I command
+before executing it.
+.SH EXAMPLES
+.TP 15
+.B "descend ls"
+Cheap substitute for `ls -R'.
+.TP 15
+.B "descend -f 'rm *' tree"
+Strip `tree' of its leaves. This command descends the `tree'
+directory, removing all regular files. Since
+.BR rm (1)
+does not remove directories, this command leaves the directory
+structure of `tree' intact, but denuded. The
+.B \-f
+option is required to keep
+.B descend
+from quitting. You could use `rm \-f' instead.
+.TP
+.B "descend -r 'co RCS/*'" /project/src/
+Check out every RCS file under the directory
+.BR "/project/src" .
+.TP
+.B "descend -r 'cvs diff'"
+Perform CVS `diff' operation on every directory below (and including)
+the current one.
+.SH DIAGNOSTICS
+Returns 1 if errors occur (and the
+.B \-f
+option is not used). Otherwise returns 0.
+.SH SEE ALSO
+.BR find (1),
+.BR rcsintro (1),
+.BR cvs (1),
+.BR sccs (1)
+.SH AUTHOR
+Lowell Skoog
+.br
+Software Technology Group
+.br
+John Fluke Mfg. Co., Inc.
+.SH BUGS
+Shell metacharacters in
+.I command
+may have bizarre effects. In particular, compound commands
+(containing ';', '[', and ']' characters) will not work. It is best
+to enclose complicated commands in single quotes \(aa\ \(aa.
diff --git a/gnu/usr.bin/cvs/contrib/dirfns b/gnu/usr.bin/cvs/contrib/dirfns
new file mode 100644
index 000000000000..8324c4198e35
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/dirfns
@@ -0,0 +1,481 @@
+echo 'directory.3':
+sed 's/^X//' >'directory.3' <<'!'
+X.TH DIRECTORY 3 imported
+X.DA 9 Oct 1985
+X.SH NAME
+Xopendir, readdir, telldir, seekdir, rewinddir, closedir \- high-level directory operations
+X.SH SYNOPSIS
+X.B #include <sys/types.h>
+X.br
+X.B #include <ndir.h>
+X.PP
+X.SM
+X.B DIR
+X.B *opendir(filename)
+X.br
+X.B char *filename;
+X.PP
+X.SM
+X.B struct direct
+X.B *readdir(dirp)
+X.br
+X.B DIR *dirp;
+X.PP
+X.SM
+X.B long
+X.B telldir(dirp)
+X.br
+X.B DIR *dirp;
+X.PP
+X.SM
+X.B seekdir(dirp, loc)
+X.br
+X.B DIR *dirp;
+X.br
+X.B long loc;
+X.PP
+X.SM
+X.B rewinddir(dirp)
+X.br
+X.B DIR *dirp;
+X.PP
+X.SM
+X.B closedir(dirp)
+X.br
+X.B DIR *dirp;
+X.SH DESCRIPTION
+XThis library provides high-level primitives for directory scanning,
+Xsimilar to those available for 4.2BSD's (very different) directory system.
+X.\"The purpose of this library is to simulate
+X.\"the new flexible length directory names of 4.2bsd UNIX
+X.\"on top of the old directory structure of v7.
+XIt incidentally provides easy portability to and from 4.2BSD (insofar
+Xas such portability is not compromised by other 4.2/VAX dependencies).
+X.\"It allows programs to be converted immediately
+X.\"to the new directory access interface,
+X.\"so that they need only be relinked
+X.\"when moved to 4.2bsd.
+X.\"It is obtained with the loader option
+X.\".BR \-lndir .
+X.PP
+X.I Opendir
+Xopens the directory named by
+X.I filename
+Xand associates a
+X.I directory stream
+Xwith it.
+X.I Opendir
+Xreturns a pointer to be used to identify the
+X.I directory stream
+Xin subsequent operations.
+XThe pointer
+X.SM
+X.B NULL
+Xis returned if
+X.I filename
+Xcannot be accessed or is not a directory.
+X.PP
+X.I Readdir
+Xreturns a pointer to the next directory entry.
+XIt returns
+X.B NULL
+Xupon reaching the end of the directory or detecting
+Xan invalid
+X.I seekdir
+Xoperation.
+X.PP
+X.I Telldir
+Xreturns the current location associated with the named
+X.I directory stream.
+X.PP
+X.I Seekdir
+Xsets the position of the next
+X.I readdir
+Xoperation on the
+X.I directory stream.
+XThe new position reverts to the one associated with the
+X.I directory stream
+Xwhen the
+X.I telldir
+Xoperation was performed.
+XValues returned by
+X.I telldir
+Xare good only for the lifetime of the DIR pointer from
+Xwhich they are derived.
+XIf the directory is closed and then reopened,
+Xthe
+X.I telldir
+Xvalue may be invalidated
+Xdue to undetected directory compaction in 4.2BSD.
+XIt is safe to use a previous
+X.I telldir
+Xvalue immediately after a call to
+X.I opendir
+Xand before any calls to
+X.I readdir.
+X.PP
+X.I Rewinddir
+Xresets the position of the named
+X.I directory stream
+Xto the beginning of the directory.
+X.PP
+X.I Closedir
+Xcauses the named
+X.I directory stream
+Xto be closed,
+Xand the structure associated with the DIR pointer to be freed.
+X.PP
+XA
+X.I direct
+Xstructure is as follows:
+X.PP
+X.RS
+X.nf
+Xstruct direct {
+X /* unsigned */ long d_ino; /* inode number of entry */
+X unsigned short d_reclen; /* length of this record */
+X unsigned short d_namlen; /* length of string in d_name */
+X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+X};
+X.fi
+X.RE
+X.PP
+XThe
+X.I d_reclen
+Xfield is meaningless in non-4.2BSD systems and should be ignored.
+XThe use of a
+X.I long
+Xfor
+X.I d_ino
+Xis also a 4.2BSDism;
+X.I ino_t
+X(see
+X.IR types (5))
+Xshould be used elsewhere.
+XThe macro
+X.I DIRSIZ(dp)
+Xgives the minimum memory size needed to hold the
+X.I direct
+Xvalue pointed to by
+X.IR dp ,
+Xwith the minimum necessary allocation for
+X.IR d_name .
+X.PP
+XThe preferred way to search the current directory for entry ``name'' is:
+X.PP
+X.RS
+X.nf
+X len = strlen(name);
+X dirp = opendir(".");
+X if (dirp == NULL) {
+X fprintf(stderr, "%s: can't read directory .\\n", argv[0]);
+X return NOT_FOUND;
+X }
+X while ((dp = readdir(dirp)) != NULL)
+X if (dp->d_namlen == len && strcmp(dp->d_name, name) == 0) {
+X closedir(dirp);
+X return FOUND;
+X }
+X closedir(dirp);
+X return NOT_FOUND;
+X.RE
+X.\".SH LINKING
+X.\"This library is accessed by specifying ``-lndir'' as the
+X.\"last argument to the compile line, e.g.:
+X.\".PP
+X.\" cc -I/usr/include/ndir -o prog prog.c -lndir
+X.SH "SEE ALSO"
+Xopen(2),
+Xclose(2),
+Xread(2),
+Xlseek(2)
+X.SH HISTORY
+XWritten by
+XKirk McKusick at Berkeley (ucbvax!mckusick).
+XMiscellaneous bug fixes from elsewhere.
+XThe size of the data structure has been decreased to avoid excessive
+Xspace waste under V7 (where filenames are 14 characters at most).
+XFor obscure historical reasons, the include file is also available
+Xas
+X.IR <ndir/sys/dir.h> .
+XThe Berkeley version lived in a separate library (\fI\-lndir\fR),
+Xwhereas ours is
+Xpart of the C library, although the separate library is retained to
+Xmaximize compatibility.
+X.PP
+XThis manual page has been substantially rewritten to be informative in
+Xthe absence of a 4.2BSD manual.
+X.SH BUGS
+XThe
+X.I DIRSIZ
+Xmacro actually wastes a bit of space due to some padding requirements
+Xthat are an artifact of 4.2BSD.
+X.PP
+XThe returned value of
+X.I readdir
+Xpoints to a static area that will be overwritten by subsequent calls.
+X.PP
+XThere are some unfortunate name conflicts with the \fIreal\fR V7
+Xdirectory structure definitions.
+!
+echo 'dir.h':
+sed 's/^X//' >'dir.h' <<'!'
+X/* dir.h 4.4 82/07/25 */
+X
+X/*
+X * A directory consists of some number of blocks of DIRBLKSIZ
+X * bytes, where DIRBLKSIZ is chosen such that it can be transferred
+X * to disk in a single atomic operation (e.g. 512 bytes on most machines).
+X *
+X * Each DIRBLKSIZ byte block contains some number of directory entry
+X * structures, which are of variable length. Each directory entry has
+X * a struct direct at the front of it, containing its inode number,
+X * the length of the entry, and the length of the name contained in
+X * the entry. These are followed by the name padded to a 4 byte boundary
+X * with null bytes. All names are guaranteed null terminated.
+X * The maximum length of a name in a directory is MAXNAMLEN.
+X *
+X * The macro DIRSIZ(dp) gives the amount of space required to represent
+X * a directory entry. Free space in a directory is represented by
+X * entries which have dp->d_reclen >= DIRSIZ(dp). All DIRBLKSIZ bytes
+X * in a directory block are claimed by the directory entries. This
+X * usually results in the last entry in a directory having a large
+X * dp->d_reclen. When entries are deleted from a directory, the
+X * space is returned to the previous entry in the same directory
+X * block by increasing its dp->d_reclen. If the first entry of
+X * a directory block is free, then its dp->d_ino is set to 0.
+X * Entries other than the first in a directory do not normally have
+X * dp->d_ino set to 0.
+X */
+X#define DIRBLKSIZ 512
+X#ifdef VMUNIX
+X#define MAXNAMLEN 255
+X#else
+X#define MAXNAMLEN 14
+X#endif
+X
+Xstruct direct {
+X /* unsigned */ long d_ino; /* inode number of entry */
+X unsigned short d_reclen; /* length of this record */
+X unsigned short d_namlen; /* length of string in d_name */
+X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+X};
+X
+X/*
+X * The DIRSIZ macro gives the minimum record length which will hold
+X * the directory entry. This requires the amount of space in struct direct
+X * without the d_name field, plus enough space for the name with a terminating
+X * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
+X */
+X#undef DIRSIZ
+X#define DIRSIZ(dp) \
+X ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
+X
+X#ifndef KERNEL
+X/*
+X * Definitions for library routines operating on directories.
+X */
+Xtypedef struct _dirdesc {
+X int dd_fd;
+X long dd_loc;
+X long dd_size;
+X char dd_buf[DIRBLKSIZ];
+X} DIR;
+X#ifndef NULL
+X#define NULL 0
+X#endif
+Xextern DIR *opendir();
+Xextern struct direct *readdir();
+Xextern long telldir();
+X#ifdef void
+Xextern void seekdir();
+Xextern void closedir();
+X#endif
+X#define rewinddir(dirp) seekdir((dirp), (long)0)
+X#endif KERNEL
+!
+echo 'makefile':
+sed 's/^X//' >'makefile' <<'!'
+XDIR = closedir.o opendir.o readdir.o seekdir.o telldir.o
+XCFLAGS=-O -I. -Dvoid=int
+XDEST=..
+X
+Xall: $(DIR)
+X
+Xmv: $(DIR)
+X mv $(DIR) $(DEST)
+X
+Xcpif: dir.h
+X cp dir.h /usr/include/ndir.h
+X
+Xclean:
+X rm -f *.o
+!
+echo 'closedir.c':
+sed 's/^X//' >'closedir.c' <<'!'
+Xstatic char sccsid[] = "@(#)closedir.c 4.2 3/10/82";
+X
+X#include <sys/types.h>
+X#include <dir.h>
+X
+X/*
+X * close a directory.
+X */
+Xvoid
+Xclosedir(dirp)
+X register DIR *dirp;
+X{
+X close(dirp->dd_fd);
+X dirp->dd_fd = -1;
+X dirp->dd_loc = 0;
+X free((char *)dirp);
+X}
+!
+echo 'opendir.c':
+sed 's/^X//' >'opendir.c' <<'!'
+X/* Copyright (c) 1982 Regents of the University of California */
+X
+Xstatic char sccsid[] = "@(#)opendir.c 4.4 11/12/82";
+X
+X#include <sys/types.h>
+X#include <sys/stat.h>
+X#include <dir.h>
+X
+X/*
+X * open a directory.
+X */
+XDIR *
+Xopendir(name)
+X char *name;
+X{
+X register DIR *dirp;
+X register int fd;
+X struct stat statbuf;
+X char *malloc();
+X
+X if ((fd = open(name, 0)) == -1)
+X return NULL;
+X if (fstat(fd, &statbuf) == -1 || !(statbuf.st_mode & S_IFDIR)) {
+X close(fd);
+X return NULL;
+X }
+X if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
+X close (fd);
+X return NULL;
+X }
+X dirp->dd_fd = fd;
+X dirp->dd_loc = 0;
+X dirp->dd_size = 0; /* so that telldir will work before readdir */
+X return dirp;
+X}
+!
+echo 'readdir.c':
+sed 's/^X//' >'readdir.c' <<'!'
+X/* Copyright (c) 1982 Regents of the University of California */
+X
+Xstatic char sccsid[] = "@(#)readdir.c 4.3 8/8/82";
+X
+X#include <sys/types.h>
+X#include <dir.h>
+X
+X/*
+X * read an old stlye directory entry and present it as a new one
+X */
+X#define ODIRSIZ 14
+X
+Xstruct olddirect {
+X ino_t od_ino;
+X char od_name[ODIRSIZ];
+X};
+X
+X/*
+X * get next entry in a directory.
+X */
+Xstruct direct *
+Xreaddir(dirp)
+X register DIR *dirp;
+X{
+X register struct olddirect *dp;
+X static struct direct dir;
+X
+X for (;;) {
+X if (dirp->dd_loc == 0) {
+X dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
+X DIRBLKSIZ);
+X if (dirp->dd_size <= 0) {
+X dirp->dd_size = 0;
+X return NULL;
+X }
+X }
+X if (dirp->dd_loc >= dirp->dd_size) {
+X dirp->dd_loc = 0;
+X continue;
+X }
+X dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc);
+X dirp->dd_loc += sizeof(struct olddirect);
+X if (dp->od_ino == 0)
+X continue;
+X dir.d_ino = dp->od_ino;
+X strncpy(dir.d_name, dp->od_name, ODIRSIZ);
+X dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */
+X dir.d_namlen = strlen(dir.d_name);
+X dir.d_reclen = DIRBLKSIZ;
+X return (&dir);
+X }
+X}
+!
+echo 'seekdir.c':
+sed 's/^X//' >'seekdir.c' <<'!'
+Xstatic char sccsid[] = "@(#)seekdir.c 4.9 3/25/83";
+X
+X#include <sys/param.h>
+X#include <dir.h>
+X
+X/*
+X * seek to an entry in a directory.
+X * Only values returned by "telldir" should be passed to seekdir.
+X */
+Xvoid
+Xseekdir(dirp, loc)
+X register DIR *dirp;
+X long loc;
+X{
+X long curloc, base, offset;
+X struct direct *dp;
+X extern long lseek();
+X
+X curloc = telldir(dirp);
+X if (loc == curloc)
+X return;
+X base = loc & ~(DIRBLKSIZ - 1);
+X offset = loc & (DIRBLKSIZ - 1);
+X (void) lseek(dirp->dd_fd, base, 0);
+X dirp->dd_size = 0;
+X dirp->dd_loc = 0;
+X while (dirp->dd_loc < offset) {
+X dp = readdir(dirp);
+X if (dp == NULL)
+X return;
+X }
+X}
+!
+echo 'telldir.c':
+sed 's/^X//' >'telldir.c' <<'!'
+Xstatic char sccsid[] = "@(#)telldir.c 4.1 2/21/82";
+X
+X#include <sys/types.h>
+X#include <dir.h>
+X
+X/*
+X * return a pointer into a directory
+X */
+Xlong
+Xtelldir(dirp)
+X DIR *dirp;
+X{
+X long lseek();
+X
+X return (lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc);
+X}
+!
+echo done
diff --git a/gnu/usr.bin/cvs/contrib/log.pl b/gnu/usr.bin/cvs/contrib/log.pl
new file mode 100644
index 000000000000..a6c75f6f0c6b
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/log.pl
@@ -0,0 +1,104 @@
+#!/usr/bin/perl
+
+# Modified by berliner@Sun.COM to add support for CVS 1.3 2/27/92
+#
+# Date: Tue, 6 Aug 91 13:27 EDT
+# From: samborn@sunrise.com (Kevin Samborn)
+#
+# I revised the perl script I sent you yesterday to use the info you
+# send in on stdin. (I am appending the newer script to the end)
+#
+# now the output looks like this:
+#
+# **************************************
+# date: Tuesday, August 6, 1991 @ 13:17
+# author: samborn
+# Update of /elmer/cvs/CVSROOT.adm
+# In directory astro:/home/samborn/CVSROOT.adm
+#
+# Modified Files:
+# test3
+#
+# Added Files:
+# test6
+#
+# Removed Files:
+# test4
+#
+# Log Message:
+# wow, what a test
+#
+# RCS: 1.4 /elmer/cvs/CVSROOT.adm/test3,v
+# RCS: 1.1 /elmer/cvs/CVSROOT.adm/test6,v
+# RCS: 1.1 /elmer/cvs/CVSROOT.adm/Attic/test4,v
+#
+
+#
+# turn off setgid
+#
+$) = $(;
+
+#
+# parse command line arguments
+#
+@files = split(/ /,$ARGV[0]);
+$logfile = $ARGV[1];
+$cvsroot = $ENV{'CVSROOT'};
+
+#
+# Some date and time arrays
+#
+@mos = (January,February,March,April,May,June,July,August,September,
+ October,November,December);
+@days = (Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday);
+($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime;
+
+#
+# get login name
+#
+$login = getlogin || (getpwuid($<))[0] || "nobody";
+
+#
+# open log file for appending
+#
+if ((open(OUT, ">>" . $logfile)) != 1) {
+ die "Could not open logfile " . $logfile . "\n";
+}
+
+#
+# Header
+#
+print OUT "\n";
+print OUT "**************************************\n";
+print OUT "date: " . $days[$wday] . ", " . $mos[$mon] . " " . $mday . ", 19" . $year .
+ " @ " . $hour . ":" . sprintf("%02d", $min) . "\n";
+print OUT "author: " . $login . "\n";
+
+#
+#print the stuff on stdin to the logfile
+#
+open(IN, "-");
+while(<IN>) {
+ print OUT $_;
+}
+close(IN);
+
+print OUT "\n";
+
+#
+# after log information, do an 'cvs -Qn status' on each file in the arguments.
+#
+for $file (@files[1..$#files]) {
+ if ($file eq "-") {
+ last;
+ }
+ open(RCS,"-|") || exec 'cvs', '-Qn', 'status', $file;
+ while (<RCS>) {
+ if (substr($_, 0, 7) eq " RCS") {
+ print OUT;
+ }
+ }
+ close (RCS);
+}
+
+close (OUT);
diff --git a/gnu/usr.bin/cvs/contrib/log_accum.pl b/gnu/usr.bin/cvs/contrib/log_accum.pl
new file mode 100644
index 000000000000..798e25f1f0e1
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/log_accum.pl
@@ -0,0 +1,331 @@
+#!/usr/local/bin/perl -w
+#
+# Perl filter to handle the log messages from the checkin of files in
+# a directory. This script will group the lists of files by log
+# message, and mail a single consolidated log message at the end of
+# the commit.
+#
+# This file assumes a pre-commit checking program that leaves the
+# names of the first and last commit directories in a temporary file.
+#
+# Contributed by David Hampton <hampton@cisco.com>
+#
+
+############################################################
+#
+# Configurable options
+#
+############################################################
+#
+# Do cisco Systems, Inc. specific nonsense.
+#
+$cisco_systems = 1;
+
+#
+# Recipient of all mail messages
+#
+$mailto = "sw-notification@cisco.com";
+
+############################################################
+#
+# Constants
+#
+############################################################
+$STATE_NONE = 0;
+$STATE_CHANGED = 1;
+$STATE_ADDED = 2;
+$STATE_REMOVED = 3;
+$STATE_LOG = 4;
+
+$LAST_FILE = "/tmp/#cvs.lastdir";
+$CHANGED_FILE = "/tmp/#cvs.files.changed";
+$ADDED_FILE = "/tmp/#cvs.files.added";
+$REMOVED_FILE = "/tmp/#cvs.files.removed";
+$LOG_FILE = "/tmp/#cvs.files.log";
+$FILE_PREFIX = "#cvs.files";
+
+$VERSION_FILE = "version";
+$TRUNKREV_FILE = "TrunkRev";
+$CHANGES_FILE = "Changes";
+$CHANGES_TEMP = "Changes.tmp";
+
+############################################################
+#
+# Subroutines
+#
+############################################################
+
+sub format_names {
+ local($dir, @files) = @_;
+ local(@lines);
+ $lines[0] = sprintf(" %-08s", $dir);
+ foreach $file (@files) {
+ if (length($lines[$#lines]) + length($file) > 60) {
+ $lines[++$#lines] = sprintf(" %8s", " ");
+ }
+ $lines[$#lines] .= " ".$file;
+ }
+ @lines;
+}
+
+sub cleanup_tmpfiles {
+ local($all) = @_;
+ local($wd, @files);
+
+ $wd = `pwd`;
+ chdir("/tmp");
+ opendir(DIR, ".");
+ if ($all == 1) {
+ push(@files, grep(/$id$/, readdir(DIR)));
+ } else {
+ push(@files, grep(/^$FILE_PREFIX.*$id$/, readdir(DIR)));
+ }
+ closedir(DIR);
+ foreach (@files) {
+ unlink $_;
+ }
+ chdir($wd);
+}
+
+sub write_logfile {
+ local($filename, @lines) = @_;
+ open(FILE, ">$filename") || die ("Cannot open log file $filename.\n");
+ print(FILE join("\n", @lines), "\n");
+ close(FILE);
+}
+
+sub append_to_file {
+ local($filename, $dir, @files) = @_;
+ if (@files) {
+ local(@lines) = &format_names($dir, @files);
+ open(FILE, ">>$filename") || die ("Cannot open file $filename.\n");
+ print(FILE join("\n", @lines), "\n");
+ close(FILE);
+ }
+}
+
+sub write_line {
+ local($filename, $line) = @_;
+ open(FILE, ">$filename") || die("Cannot open file $filename.\n");
+ print(FILE $line, "\n");
+ close(FILE);
+}
+
+sub read_line {
+ local($line);
+ local($filename) = @_;
+ open(FILE, "<$filename") || die("Cannot open file $filename.\n");
+ $line = <FILE>;
+ close(FILE);
+ chop($line);
+ $line;
+}
+
+sub read_file {
+ local(@text);
+ local($filename, $leader) = @_;
+ open(FILE, "<$filename") || return ();
+ while (<FILE>) {
+ chop;
+ push(@text, sprintf(" %-10s %s", $leader, $_));
+ $leader = "";
+ }
+ close(FILE);
+ @text;
+}
+
+sub read_logfile {
+ local(@text);
+ local($filename, $leader) = @_;
+ open(FILE, "<$filename") || die ("Cannot open log file $filename.\n");
+ while (<FILE>) {
+ chop;
+ push(@text, $leader.$_);
+ }
+ close(FILE);
+ @text;
+}
+
+sub bump_version {
+ local($trunkrev, $editnum, $version);
+
+ $trunkrev = &read_line("$ENV{'CVSROOT'}/$repository/$TRUNKREV_FILE");
+ $editnum = &read_line("$ENV{'CVSROOT'}/$repository/$VERSION_FILE");
+ &write_line("$ENV{'CVSROOT'}/$repository/$VERSION_FILE", $editnum+1);
+ $version = $trunkrev . "(" . $editnum . ")";
+}
+
+sub build_header {
+ local($version) = @_;
+ local($header);
+ local($sec,$min,$hour,$mday,$mon,$year) = localtime(time);
+ $header = sprintf("%-8s %s %02d/%02d/%02d %02d:%02d:%02d",
+ $login, $version, $year%100, $mon+1, $mday,
+ $hour, $min, $sec);
+}
+
+sub do_changes_file {
+ local($changes, $tmpchanges);
+ local(@text) = @_;
+
+ $changes = "$ENV{'CVSROOT'}/$repository/$CHANGES_FILE";
+ $tmpchanges = "$ENV{'CVSROOT'}/$repository/$CHANGES_TEMP";
+ if (rename($changes, $tmpchanges) != 1) {
+ die("Cannot rename $changes to $tmpchanges.\n");
+ }
+ open(CHANGES, ">$changes") || die("Cannot open $changes.\n");
+ open(TMPCHANGES, "<$tmpchanges") || die("Cannot open $tmpchanges.\n");
+ print(CHANGES join("\n", @text), "\n\n");
+ print(CHANGES <TMPCHANGES>);
+ close(CHANGES);
+ close(TMPCHANGES);
+ unlink($tmpchanges);
+}
+
+sub mail_notification {
+ local($name, @text) = @_;
+ open(MAIL, "| mail -s \"Source Repository Modification\" $name");
+ print(MAIL join("\n", @text));
+ close(MAIL);
+}
+
+#############################################################
+#
+# Main Body
+#
+############################################################
+
+#
+# Initialize basic variables
+#
+$id = getpgrp();
+$state = $STATE_NONE;
+$login = getlogin || (getpwuid($<))[0] || die("Unknown user $<.\n");
+@files = split(' ', $ARGV[0]);
+@path = split('/', $files[0]);
+$repository = @path[0];
+if ($#path == 0) {
+ $dir = ".";
+} else {
+ $dir = join('/', @path[1..$#path]);
+}
+#print("ARGV - ", join(":", @ARGV), "\n");
+#print("files - ", join(":", @files), "\n");
+#print("path - ", join(":", @path), "\n");
+#print("dir - ", $dir, "\n");
+#print("id - ", $id, "\n");
+
+#
+# Check for a new directory first. This will always appear as a
+# single item in the argument list, and an empty log message.
+#
+if ($ARGV[0] =~ /New directory/) {
+ $version = &bump_version if ($cisco_systems != 0);
+ $header = &build_header($version);
+ @text = ();
+ push(@text, $header);
+ push(@text, "");
+ push(@text, " ".$ARGV[0]);
+ &do_changes_file(@text) if ($cisco_systems != 0);
+ &mail_notification($mailto, @text);
+ exit 0;
+}
+
+#
+# Iterate over the body of the message collecting information.
+#
+while (<STDIN>) {
+ chop; # Drop the newline
+ if (/^Modified Files/) { $state = $STATE_CHANGED; next; }
+ if (/^Added Files/) { $state = $STATE_ADDED; next; }
+ if (/^Removed Files/) { $state = $STATE_REMOVED; next; }
+ if (/^Log Message/) { $state = $STATE_LOG; next; }
+ s/^[ \t\n]+//; # delete leading space
+ s/[ \t\n]+$//; # delete trailing space
+
+ push (@changed_files, split) if ($state == $STATE_CHANGED);
+ push (@added_files, split) if ($state == $STATE_ADDED);
+ push (@removed_files, split) if ($state == $STATE_REMOVED);
+ push (@log_lines, $_) if ($state == $STATE_LOG);
+}
+
+#
+# Strip leading and trailing blank lines from the log message. Also
+# compress multiple blank lines in the body of the message down to a
+# single blank line.
+#
+while ($#log_lines > -1) {
+ last if ($log_lines[0] ne "");
+ shift(@log_lines);
+}
+while ($#log_lines > -1) {
+ last if ($log_lines[$#log_lines] ne "");
+ pop(@log_lines);
+}
+for ($i = $#log_lines; $i > 0; $i--) {
+ if (($log_lines[$i - 1] eq "") && ($log_lines[$i] eq "")) {
+ splice(@log_lines, $i, 1);
+ }
+}
+
+#
+# Find the log file that matches this log message
+#
+for ($i = 0; ; $i++) {
+ last if (! -e "$LOG_FILE.$i.$id");
+ @text = &read_logfile("$LOG_FILE.$i.$id", "");
+ last if ($#text == -1);
+ last if (join(" ", @log_lines) eq join(" ", @text));
+}
+
+#
+# Spit out the information gathered in this pass.
+#
+&write_logfile("$LOG_FILE.$i.$id", @log_lines);
+&append_to_file("$ADDED_FILE.$i.$id", $dir, @added_files);
+&append_to_file("$CHANGED_FILE.$i.$id", $dir, @changed_files);
+&append_to_file("$REMOVED_FILE.$i.$id", $dir, @removed_files);
+
+#
+# Check whether this is the last directory. If not, quit.
+#
+$_ = &read_line("$LAST_FILE.$id");
+exit 0 if (! grep(/$files[0]$/, $_));
+
+#
+# This is it. The commits are all finished. Lump everything together
+# into a single message, fire a copy off to the mailing list, and drop
+# it on the end of the Changes file.
+#
+# Get the full version number
+#
+$version = &bump_version if ($cisco_systems != 0);
+$header = &build_header($version);
+
+#
+# Produce the final compilation of the log messages
+#
+@text = ();
+push(@text, $header);
+push(@text, "");
+for ($i = 0; ; $i++) {
+ last if (! -e "$LOG_FILE.$i.$id");
+ push(@text, &read_file("$CHANGED_FILE.$i.$id", "Modified:"));
+ push(@text, &read_file("$ADDED_FILE.$i.$id", "Added:"));
+ push(@text, &read_file("$REMOVED_FILE.$i.$id", "Removed:"));
+ push(@text, " Log:");
+ push(@text, &read_logfile("$LOG_FILE.$i.$id", " "));
+ push(@text, "");
+}
+if ($cisco_systems != 0) {
+ @ddts = grep(/^CSCdi/, split(' ', join(" ", @text)));
+ $text[0] .= " " . join(" ", @ddts);
+}
+#
+# Put the log message at the beginning of the Changes file and mail
+# out the notification.
+#
+&do_changes_file(@text) if ($cisco_systems != 0);
+&mail_notification($mailto, @text);
+&cleanup_tmpfiles(1);
+exit 0;
diff --git a/gnu/usr.bin/cvs/contrib/mfpipe.pl b/gnu/usr.bin/cvs/contrib/mfpipe.pl
new file mode 100644
index 000000000000..74cc5e1e8d06
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/mfpipe.pl
@@ -0,0 +1,87 @@
+#!/usr/bin/perl
+#
+# From: clyne@niwot.scd.ucar.EDU (John Clyne)
+# Date: Fri, 28 Feb 92 09:54:21 MST
+#
+# BTW, i wrote a perl script that is similar to 'nfpipe' except that in
+# addition to logging to a file it provides a command line option for mailing
+# change notices to a group of users. Obviously you probably wouldn't want
+# to mail every change. But there may be certain directories that are commonly
+# accessed by a group of users who would benefit from an email notice.
+# Especially if they regularly beat on the same directory. Anyway if you
+# think anyone would be interested here it is.
+#
+# mfpipe.pl,v 1.1 1992/03/02 01:22:41 berliner Exp
+#
+#
+# File: mfpipe
+#
+# Author: John Clyne
+# National Center for Atmospheric Research
+# PO 3000, Boulder, Colorado
+#
+# Date: Wed Feb 26 18:34:53 MST 1992
+#
+# Description: Tee standard input to mail a list of users and to
+# a file. Used by CVS logging.
+#
+# Usage: mfpipe [-f file] [user@host...]
+#
+# Environment: CVSROOT
+# Path to CVS root.
+#
+# Files:
+#
+#
+# Options: -f file
+# Capture output to 'file'
+#
+
+$header = "Log Message:\n";
+
+$mailcmd = "| mail -s 'CVS update notice'";
+$whoami = `whoami`;
+chop $whoami;
+$date = `date`;
+chop $date;
+
+$cvsroot = $ENV{'CVSROOT'};
+
+while (@ARGV) {
+ $arg = shift @ARGV;
+
+ if ($arg eq '-f') {
+ $file = shift @ARGV;
+ }
+ else {
+ $users = "$users $arg";
+ }
+}
+
+if ($users) {
+ $mailcmd = "$mailcmd $users";
+ open(MAIL, $mailcmd) || die "Execing $mail: $!\n";
+}
+
+if ($file) {
+ $logfile = "$cvsroot/LOG/$file";
+ open(FILE, ">> $logfile") || die "Opening $logfile: $!\n";
+}
+
+print FILE "$whoami $date--------BEGIN LOG ENTRY-------------\n" if ($logfile);
+
+while (<>) {
+ print FILE $log if ($log && $logfile);
+
+ print FILE $_ if ($logfile);
+ print MAIL $_ if ($users);
+
+ $log = "log: " if ($_ eq $header);
+}
+
+close FILE;
+die "Write failed" if $?;
+close MAIL;
+die "Mail failed" if $?;
+
+exit 0;
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/ChangeLog b/gnu/usr.bin/cvs/contrib/pcl-cvs/ChangeLog
new file mode 100644
index 000000000000..fab9a7dc9a36
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/ChangeLog
@@ -0,0 +1,119 @@
+Tue Apr 7 09:11:27 1992 Per Cederqvist (ceder@leopold)
+
+ * Release 1.02.
+
+ * pcl-cvs.el (cvs-diff-backup, cvs-edit-done, cvs-status): Call
+ save-some-buffers.
+
+ * pcl-cvs.el (cvs-diff-backup-extractor): Fixed syntax error.
+
+ * Makefile, README, compile-all.el, dist-makefile, pcl-cvs.el,
+ pcl-cvs.texinfo (XXRELEASEXX): A magic string that is substituted
+ for the current release number when a distribution is made.
+ (Release 1.01 says that it is release 1.00).
+
+ * pcl-cvs.el (cvs-find-file): Added missing pair of parenthesis.
+
+Mon Mar 30 14:25:26 1992 Per Cederqvist (ceder@leopold)
+
+ * Release 1.01.
+
+ * pcl-cvs.el (cvs-parse-buffer): The message when waiting for a
+ lock has been changed.
+
+Sun Mar 29 05:29:57 1992 Per Cederqvist (ceder@leopold)
+
+ * Release 1.00.
+
+ * pcl-cvs.el (cvs-do-update, cvs-sentinel, cvs-parse-buffer):
+ Major rewrite of buffer and window selection and handling.
+ The *cvs* buffer is now killed whenever a new "cvs update" is
+ initiated. The -update buffer is replaced with the *cvs*
+ buffer when the update is completed.
+
+Sat Mar 28 21:03:05 1992 Per Cederqvist (ceder@robin)
+
+ * pcl-cvs.el (cvs-delete-unused-temporary-buffers): Fixed it.
+
+ * pcl-cvs.el (cvs-auto-remove-handled): New variable.
+ * pcl-cvs.el (cvs-edit-done): Use it.
+ * pcl-cvs.texinfo (Customization, Removing handled entries):
+ Document it.
+
+ * pcl-cvs.el (cvs-mode): Turn of the undo feature. It really
+ isn't useful in a cookie buffer...
+
+ * pcl-cvs.el (cvs-edit-done): Committing a file now looks more
+ like diffing a file. The window handling is better.
+ * pcl-cvs.el (cvs-use-temp-buffer): The &optional switch is no
+ longer needed.
+
+Mon Mar 23 00:20:33 1992 Per Cederqvist (ceder@robin)
+
+ * Release 0.97.
+
+ * pcl-cvs.el (default-directory): Make sure it always ends in a
+ slash. fileinfo->dir does NOT end in a slash, and I had forgotten
+ to call file-name-as-directory in various places.
+
+ * pcl-cvs.el (cvs-diff-backup-extractor): Signal an error if a
+ fileinfo without backup file is given.
+
+ * pcl-cvs.el (cvs-mode): Added documentation.
+
+ * pcl-cvs.el (cvs-execute-list): Fix the order of files in the
+ same directory.
+
+ * pcl-cvs.el (cvs-log-flags, cvs-status-flags): New variables.
+ * pcl-cvs.el (cvs-log, cvs-status): Use them.
+ * pcl-cvs.texinfo (Customization): Document them.
+
+ * pcl-cvs.el (cvs-diff-backup): Filter non-backup-diffable files
+ at an earlier stage, like cvs-commit does.
+
+ * pcl-cvs.el (cvs-diff-flags): New variable.
+ * pcl-cvs.el (cvs-diff-backup): Use it.
+ * pcl-cvs.texinfo (Customization): Document it.
+
+ * pcl-cvs.el (cvs-execute-single-file-list): Remove &rest before
+ last argument. No callers needed updating.
+
+ * pcl-cvs.el (cvs-execute-list): Remove the &rest before the last
+ argument (constant-args). Update all callers of cvs-execute-list
+ to use the new calling convention.
+ * pcl-cvs.el (cvs-cvs-diff-flags): Now a list of strings instead
+ of a string.
+ * pcl-cvs.texinfo (Customization): Document the change to
+ cvs-cvs-diff-flags.
+
+ * Release 0.96.
+
+ * pcl-cvs.el (cvs-cvs-diff-flags): New variable.
+ * pcl-cvs.el (cvs-diff-cvs): Use it.
+ * pcl-cvs.texinfo (Customization, Viewing differences): Document it.
+
+ * pcl-cvs.el (cvs-use-temp-buffe): Don't switch to the temporary
+ buffer. Use display-buffer and set-buffer instead. This way
+ cvs-log, cvs-status, cvs-diff-cvs and friends don't select the
+ temporary buffer. The cursor will remain in the *cvs* buffer.
+
+Sun Mar 22 21:50:18 1992 Per Cederqvist (ceder@robin)
+
+ * pcl-cvs.el (cvs-find-file, cvs-find-file-other-window): Don't
+ prompt when reading in a directory in dired.
+
+ * Makefile (pcl-cvs-$(VER)): Include pcl-cvs-startup.el in the
+ distribution.
+
+ * dist-makefile (pcl-cvs.dvi): Don't fail even if texindex does
+ not exist.
+
+ * pcl-cvs.texinfo (@setchapternewpage): Changed from 'off' to 'on'.
+ * pcl-cvs.texinfo (Variable index): Joined into function index.
+ * pcl-cvs.texinfo (Key index): add a description about the key.
+ * pcl-cvs.texinfo: Many other small changes.
+
+Wed Mar 18 01:58:38 1992 Per Cederqvist (ceder@leopold)
+
+ * Use GNU General Public License version 2.
+
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/INSTALL b/gnu/usr.bin/cvs/contrib/pcl-cvs/INSTALL
new file mode 100644
index 000000000000..8c89053d9674
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/INSTALL
@@ -0,0 +1,83 @@
+This text is copied from the TeXinfo manual for pcl-cvs.
+
+Installation of the pcl-cvs program
+===================================
+
+ 1. Edit the file `Makefile' to reflect the situation at your site.
+ The only things you have to change is the definition of
+ `lispdir' and `infodir'. The elisp files will be copied to
+ `lispdir', and the info file to `infodir'.
+
+ 2. Configure pcl-cvs.el
+
+ There are a couple of paths that you have to check to make
+ sure that they match you system. They appear early in the file
+ pcl-cvs.el.
+
+ *NOTE:* If your system is running emacs 18.57 or earlier
+ you MUST uncomment the line that says:
+
+ (setq delete-exited-processes nil)
+
+ Setting `delete-exited-processes' to `nil' works around a bug
+ in emacs that causes it to dump core. The bug was fixed in
+ emacs 18.58.
+
+ 3. Type `make install' in the source directory. This will
+ byte-compile all `.el' files and copy both the `.el' and the
+ `.elc' into the directory you specified in step 1.
+
+ If you don't want to install the `.el' files but only the
+ `.elc' files (the byte-compiled files), you can type ``make
+ install_elc'' instead of ``make install''.
+
+ If you only want to create the compiled elisp files, but
+ don't want to install them, you can type `make elcfiles'
+ instead. This is what happens if you only type `make' without
+ parameters.
+
+ 4. Edit the file `default.el' in your emacs lisp directory (usually
+ `/usr/gnu/emacs/lisp' or something similar) and enter the
+ contents of the file `pcl-cvs-startup.el' into it. It contains
+ a couple of `auto-load's that facilitates the use of pcl-cvs.
+
+
+
+
+Installation of the on-line manual.
+===================================
+
+ 1. Create the info file `pcl-cvs' from `pcl-cvs.texinfo' by typing
+ `make info'. If you don't have the program `makeinfo' you can
+ get it by anonymous ftp from e.g. `ftp.gnu.ai.mit.edu' as
+ `pub/gnu/texinfo-2.14.tar.Z' (there might be a newer version
+ there when you read this), or you could use the preformatted
+ info file `pcl-cvs.info' that is included in the distribution
+ (type `cp pcl-cvs.info pcl-cvs').
+
+ 2. Move the info file `pcl-cvs' to your standard info directory.
+ This might be called something like `/usr/gnu/emacs/info'.
+
+ 3. Edit the file `dir' in the info directory and enter one line to
+ contain a pointer to the info file `pcl-cvs'. The line can, for
+ instance, look like this:
+
+ * Pcl-cvs: (pcl-cvs). An Emacs front-end to CVS.
+
+
+
+
+How to make typeset documentation from pcl-cvs.texinfo
+======================================================
+
+ If you have TeX installed at your site, you can make a typeset
+manual from `pcl-cvs.texinfo'.
+
+ 1. Run TeX by typing ``make pcl-cvs.dvi''. You will not get the
+ indices unless you have the `texindex' program.
+
+ 2. Convert the resulting device independent file `pcl-cvs.dvi' to a
+ form which your printer can output and print it. If you have a
+ postscript printer there is a program, `dvi2ps', which does.
+ There is also a program which comes together with TeX, `dvips',
+ which you can use.
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile b/gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile
new file mode 100644
index 000000000000..f0ded69d19a7
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile
@@ -0,0 +1,78 @@
+# Makefile,v 1.2 1992/04/07 20:49:07 berliner Exp
+# Makefile for pcl-cvs release 1.02.
+# Copyright (C) 1992 Per Cederqvist
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# This is the directory in which the ELFILES and ELCFILES will be
+# installed.
+
+lispdir = /usr/local/lib/elisp
+
+# Where to install the info file.
+
+prefix=/usr/local
+infodir = $(prefix)/info
+
+#
+# The rest of this file should not need to be modified.
+#
+
+# Just in case...
+SHELL = /bin/sh
+
+ELFILES = pcl-cvs.el cookie.el elib-dll.el elib-node.el
+ELCFILES = pcl-cvs.elc cookie.elc elib-dll.elc elib-node.elc
+INFOFILES = pcl-cvs
+TEXTMPS = pcl-cvs.aux pcl-cvs.log pcl-cvs.toc pcl-cvs.dvi pcl-cvs.cp \
+ pcl-cvs.fn pcl-cvs.vr pcl-cvs.tp pcl-cvs.ky pcl-cvs.pg \
+ pcl-cvs.cps pcl-cvs.fns pcl-cvs.kys pcl-cvs.pgs pcl-cvs.tps \
+ pcl-cvs.vrs
+
+INSTALL = install
+INSTALL_DATA = $(INSTALL)
+
+elcfiles:
+ emacs -batch -l ./compile-all.el -f compile-pcl-cvs
+
+all: elcfiles info
+
+# Don't install the info file yet, since it requires makeinfo
+# version 2.something (and version 1.something is distributed with emacs).
+#
+# install: install_elc install_info
+install: install_elc
+ for i in $(ELFILES); do $(INSTALL_DATA) $$i $(lispdir)/$$i; done
+
+install_elc: elcfiles
+ for i in $(ELCFILES); do $(INSTALL_DATA) $$i $(lispdir)/$$i; done
+
+install_info: pcl-cvs
+ $(INSTALL_DATA) pcl-cvs $(infodir)/pcl-cvs
+
+info pcl-cvs: pcl-cvs.texinfo
+ makeinfo +fill-column=70 pcl-cvs.texinfo
+
+pcl-cvs.dvi: pcl-cvs.texinfo
+ tex pcl-cvs.texinfo
+ -texindex pcl-cvs.cp pcl-cvs.fn pcl-cvs.vr pcl-cvs.tp pcl-cvs.ky \
+ pcl-cvs.pg
+ tex pcl-cvs.texinfo
+
+mostlyclean clean realclean:
+ rm -f *~ core $(ELCFILES) $(INFOFILES) $(TEXTMPS)
+
+tags TAGS:
+ etags *.el
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/README b/gnu/usr.bin/cvs/contrib/pcl-cvs/README
new file mode 100644
index 000000000000..6f0a5feb2675
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/README
@@ -0,0 +1,14 @@
+README,v 1.2 1992/04/07 20:49:09 berliner Exp
+
+This is the readme file for pcl-cvs, release 1.02.
+
+Pcl-cvs is a front-end to CVS version 1.3. It integrates the most
+frequently used CVS commands into emacs.
+
+There is some configuration that needs to be done in pcl-cvs.el to get
+it to work. See the instructions in file INSTALL.
+
+Full documentation is in pcl-cvs.texinfo. Since it requires makeinfo
+2.14 a preformatted info file is also included (pcl-cvs.info).
+
+ ceder@lysator.liu.se
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/compile-all.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/compile-all.el
new file mode 100644
index 000000000000..74f1bca1b215
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/compile-all.el
@@ -0,0 +1,52 @@
+;;;; compile-all.el,v 1.2 1992/04/07 20:49:10 berliner Exp
+;;;; This file byte-compiles all .el files in pcl-cvs release 1.02.
+;;;;
+;;;; Copyright (C) 1991 Inge Wallin
+;;;;
+;;;; This file is part of the GNU Emacs lisp library, Elib.
+;;;;
+;;;; GNU Elib is free software; you can redistribute it and/or modify
+;;;; it under the terms of the GNU General Public License as published by
+;;;; the Free Software Foundation; either version 1, or (at your option)
+;;;; any later version.
+;;;;
+;;;; GNU Elib is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;;; GNU General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU General Public License
+;;;; along with GNU Emacs; see the file COPYING. If not, write to
+;;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+;;;;
+
+
+(setq elib-files '("elib-node"
+ "elib-dll"
+ "cookie"
+ "pcl-cvs"))
+
+
+(defun compile-file-if-necessary (file)
+ "Compile the Elib file FILE if necessary.
+
+This is done if FILE.el is newer than FILE.elc or if FILE.elc doesn't exist."
+ (let ((el-name (concat file ".el"))
+ (elc-name (concat file ".elc")))
+ (if (or (not (file-exists-p elc-name))
+ (file-newer-than-file-p el-name elc-name))
+ (progn
+ (message (format "Byte-compiling %s..." el-name))
+ (byte-compile-file el-name)))))
+
+
+(defun compile-pcl-cvs ()
+ "Byte-compile all uncompiled files of elib.
+Be sure to have . in load-path since a number of files in elib
+depend on other files and we always want the newer one even if
+a previous version of elib exists."
+
+ (interactive)
+ (setq load-path (append '(".") load-path))
+ (mapcar (function compile-file-if-necessary)
+ elib-files))
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/cookie.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/cookie.el
new file mode 100644
index 000000000000..8bd4bdff6ce0
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/cookie.el
@@ -0,0 +1,884 @@
+;;; cookie.el,v 1.2 1992/04/07 20:49:12 berliner Exp
+;;; cookie.el -- Utility to display cookies in buffers
+;;; Copyright (C) 1991, 1992 Per Cederqvist
+;;;
+;;; This program is free software; you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 2 of the License, or
+;;; (at your option) any later version.
+;;;
+;;; This program is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with this program; if not, write to the Free Software
+;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;;; TO-DO: Byt namn! tin -> wrapper (eller n}got b{ttre).
+
+;;; Note that this file is still under development. Comments,
+;;; enhancements and bug fixes are welcome.
+;;; Send them to ceder@lysator.liu.se.
+
+(defun impl nil (error "Not yet implemented!"))
+
+;;; Cookie is a package that imlements a connection between an
+;;; elib-dll and the contents of a buffer. Possible uses are dired
+;;; (have all files in a list, and show them), buffer-list,
+;;; kom-prioritize (in the LysKOM elisp client) and others. pcl-cvs.el
+;;; uses cookie.el.
+;;;
+;;; A cookie buffer contains a header, any number of cookies, and a
+;;; footer. The header and footer are constant strings that are given
+;;; to cookie-create when the buffer is placed under cookie. Each cookie
+;;; is displayed in the buffer by calling a user-supplied function
+;;; that takes a cookie and returns a string. The string may be
+;;; empty, or contain any number of lines. An extra newline is always
+;;; appended unless the string is empty.
+;;;
+;;; Cookie does not affect the mode of the buffer in any way. It
+;;; merely makes it easy to connect an underlying data representation
+;;; to the buffer contents.
+;;;
+;;; The cookie-node data type:
+;;; start-marker
+;;; ;; end-marker This field is no longer present.
+;;; cookie The user-supplied element.
+;;;
+;;; A dll of cookie-nodes are held in the buffer local variable
+;;; cake-tin.
+;;;
+;;; A tin is an object that contains one cookie. You can get the next
+;;; and previous tin.
+;;;
+
+(require 'elib-dll)
+(provide 'cookie)
+
+(defvar cookies nil
+ "A doubly linked list that contains the underlying data representation
+for the contents of a cookie buffer. The package elib-dll is used to
+manipulate this list.")
+
+(defvar cookie-pretty-printer nil
+ "The function that is used to pretty-print a cookie in this buffer.")
+
+(defvar cookie-header nil
+ "The tin that holds the header cookie.")
+
+(defvar cookie-footer nil
+ "The tin that holds the footer cookie.")
+
+(defvar cookie-last-tin nil
+ "The tin the cursor was positioned at, the last time the cookie
+package checked the cursor position. Buffer local in all buffers
+the cookie package works on. You may set this if your package
+thinks it knows where the cursor will be the next time this
+package is called. It can speed things up.
+
+It must never be set to a tin that has been deleted.")
+
+;;; ================================================================
+;;; Internal functions for use in the cookie package
+
+(put 'cookie-set-buffer 'lisp-indent-hook 1)
+
+(defmacro cookie-set-buffer (buffer &rest forms)
+
+ ;; Execute FORMS with BUFFER selected as current buffer.
+ ;; Return value of last form in FORMS. INTERNAL USE ONLY.
+
+ (let ((old-buffer (make-symbol "old-buffer")))
+ (` (let (((, old-buffer) (current-buffer)))
+ (set-buffer (get-buffer-create (, buffer)))
+ (unwind-protect
+ (progn (,@ forms))
+ (set-buffer (, old-buffer)))))))
+
+
+(defmacro cookie-filter-hf (tin)
+
+ ;; Evaluate TIN once and return it. BUT if it is
+ ;; equal to cookie-header or cookie-footer return nil instead.
+ ;; INTERNAL USE ONLY.
+
+ (let ((tempvar (make-symbol "tin")))
+ (` (let (((, tempvar) (, tin)))
+ (if (or (eq (, tempvar) cookie-header)
+ (eq (, tempvar) cookie-footer))
+ nil
+ (, tempvar))))))
+
+
+;;; cookie-tin
+;;; Constructor:
+
+(defun cookie-create-tin (start-marker
+ cookie)
+ ;; Create a tin. INTERNAL USE ONLY.
+ (cons 'COOKIE-TIN (vector start-marker nil cookie)))
+
+
+;;; Selectors:
+
+(defun cookie-tin-start-marker (cookie-tin)
+ ;; Get start-marker from cookie-tin. INTERNAL USE ONLY.
+ (elt (cdr cookie-tin) 0))
+
+;(defun cookie-tin-end-marker (cookie-tin)
+; ;;Get end-marker from cookie-tin. INTERNAL USE ONLY.
+; (elt (cdr cookie-tin) 1))
+
+(defun cookie-tin-cookie-safe (cookie-tin)
+ ;; Get cookie from cookie-tin. INTERNAL USE ONLY.
+ ;; Returns nil if given nil as input.
+ ;; This is the same as cookie-tin-cookie in version 18.57
+ ;; of emacs, but elt should signal an error when given nil
+ ;; as input (according to the info files).
+ (elt (cdr cookie-tin) 2))
+
+(defun cookie-tin-cookie (cookie-tin)
+ ;; Get cookie from cookie-tin. INTERNAL USE ONLY.
+ (elt (cdr cookie-tin) 2))
+
+
+;;; Modifiers:
+
+(defun set-cookie-tin-start-marker (cookie-tin newval)
+ ;; Set start-marker in cookie-tin to NEWVAL. INTERNAL USE ONLY.
+ (aset (cdr cookie-tin) 0 newval))
+
+;(defun set-cookie-tin-end-marker (cookie-tin newval)
+; ;; Set end-marker in cookie-tin to NEWVAL. INTERNAL USE ONLY.
+; (aset (cdr cookie-tin) 1 newval))
+
+(defun set-cookie-tin-cookie (cookie-tin newval)
+ ;; Set cookie in cookie-tin to NEWVAL. INTERNAL USE ONLY.
+ (aset (cdr cookie-tin) 2 newval))
+
+
+
+;;; Predicate:
+
+(defun cookie-tin-p (object)
+ ;; Return t if OBJECT is a tin. INTERNAL USE ONLY.
+ (eq (car-safe object) 'COOKIE-TIN))
+
+;;; end of cookie-tin data type.
+
+
+(defun cookie-create-tin-and-insert (cookie string pos)
+ ;; Insert STRING at POS in current buffer. Remember start
+ ;; position. Create a tin containing them and the COOKIE.
+ ;; INTERNAL USE ONLY.
+
+ (save-excursion
+ (goto-char pos)
+ ;; Remember the position as a number so that it doesn't move
+ ;; when we insert the string.
+ (let ((start (if (markerp pos)
+ (marker-position pos)
+ pos)))
+ ;; Use insert-before-markers so that the marker for the
+ ;; next cookie is updated.
+ (insert-before-markers string)
+ (insert-before-markers ?\n)
+ (cookie-create-tin (copy-marker start) cookie))))
+
+
+(defun cookie-delete-tin-internal (tin)
+ ;; Delete a cookie from the buffer. INTERNAL USE ONLY.
+ ;; Can not be used on the footer.
+ (delete-region (cookie-tin-start-marker (dll-element cookies tin))
+ (cookie-tin-start-marker
+ (dll-element cookies
+ (dll-next cookies tin)))))
+
+
+
+(defun cookie-refresh-tin (tin)
+ ;; Redisplay the cookie represented by TIN. INTERNAL USE ONLY.
+ ;; Can not be used on the footer.
+
+ (save-excursion
+ ;; First, remove the string:
+ (delete-region (cookie-tin-start-marker (dll-element cookies tin))
+ (1- (marker-position
+ (cookie-tin-start-marker
+ (dll-element cookies
+ (dll-next cookies tin))))))
+
+ ;; Calculate and insert the string.
+
+ (goto-char (cookie-tin-start-marker (dll-element cookies tin)))
+ (insert
+ (funcall cookie-pretty-printer
+ (cookie-tin-cookie (dll-element cookies tin))))))
+
+
+;;; ================================================================
+;;; The public members of the cookie package
+
+
+(defun cookie-cookie (buffer tin)
+ "Get the cookie from a TIN. Args: BUFFER TIN."
+ (cookie-set-buffer buffer
+ (cookie-tin-cookie (dll-element cookies tin))))
+
+
+
+
+(defun cookie-create (buffer pretty-printer &optional header footer)
+
+ "Start to use the cookie package in BUFFER.
+BUFFER may be a buffer or a buffer name. It is created if it does not exist.
+Beware that the entire contents of the buffer will be erased.
+PRETTY-PRINTER is a function that takes one cookie and returns a string
+to be displayed in the buffer. The string may be empty. If it is not
+empty a newline will be added automatically. It may span several lines.
+Optional third argument HEADER is a string that will always be present
+at the top of the buffer. HEADER should end with a newline. Optionaly
+fourth argument FOOTER is similar, and will always be inserted at the
+bottom of the buffer."
+
+ (cookie-set-buffer buffer
+
+ (erase-buffer)
+
+ (make-local-variable 'cookie-last-tin)
+ (make-local-variable 'cookie-pretty-printer)
+ (make-local-variable 'cookie-header)
+ (make-local-variable 'cookie-footer)
+ (make-local-variable 'cookies)
+
+ (setq cookie-last-tin nil)
+ (setq cookie-pretty-printer pretty-printer)
+ (setq cookies (dll-create))
+
+ (dll-enter-first cookies
+ (cookie-create-tin-and-insert
+ header header 0))
+ (setq cookie-header (dll-nth cookies 0))
+
+ (dll-enter-last cookies
+ (cookie-create-tin-and-insert
+ footer footer (point-max)))
+ (setq cookie-footer (dll-nth cookies -1))
+
+ (goto-char (point-min))
+ (forward-line 1)))
+
+
+(defun cookie-set-header (buffer header)
+ "Change the header. Args: BUFFER HEADER."
+ (impl))
+
+
+(defun cookie-set-footer (buffer header)
+ "Change the footer. Args: BUFFER FOOTER."
+ (impl))
+
+
+
+(defun cookie-enter-first (buffer cookie)
+ "Enter a COOKIE first in BUFFER.
+Args: BUFFER COOKIE."
+
+ (cookie-set-buffer buffer
+
+ ;; It is always safe to insert an element after the first element,
+ ;; because the header is always present. (dll-nth cookies 0) should
+ ;; never return nil.
+
+ (dll-enter-after
+ cookies
+ (dll-nth cookies 0)
+ (cookie-create-tin-and-insert
+ cookie
+ (funcall cookie-pretty-printer cookie)
+ (cookie-tin-start-marker
+ (dll-element cookies (dll-nth cookies 1)))))))
+
+
+
+(defun cookie-enter-last (buffer cookie)
+ "Enter a COOKIE last in BUFFER.
+Args: BUFFER COOKIE."
+
+ (cookie-set-buffer buffer
+
+ ;; Remember that the header and footer are always present. There
+ ;; is no need to check if (dll-nth cookies -2) returns nil.
+
+ (dll-enter-before
+ cookies
+ (dll-nth cookies -1)
+ (cookie-create-tin-and-insert
+ cookie
+ (funcall cookie-pretty-printer cookie)
+ (cookie-tin-start-marker (dll-last cookies))))))
+
+
+(defun cookie-enter-after (buffer node cookie)
+ (impl))
+
+
+(defun cookie-enter-before (buffer node cookie)
+ (impl))
+
+
+
+(defun cookie-next (buffer tin)
+ "Get the next tin. Args: BUFFER TIN.
+Returns nil if TIN is nil or the last cookie."
+ (if tin
+ (cookie-set-buffer buffer
+ (cookie-filter-hf (dll-next cookies tin)))))
+
+
+
+(defun cookie-previous (buffer tin)
+ "Get the previous tin. Args: BUFFER TIN.
+Returns nil if TIN is nil or the first cookie."
+ (if tin
+ (cookie-set-buffer buffer
+ (cookie-filter-hf (dll-previous cookies tin)))))
+
+
+(defun cookie-nth (buffer n)
+
+ "Return the Nth tin. Args: BUFFER N.
+N counts from zero. Nil is returned if there is less than N cookies.
+If N is negative, return the -(N+1)th last element.
+Thus, (cookie-nth dll 0) returns the first node,
+and (cookie-nth dll -1) returns the last node.
+
+Use cookie-cookie to extract the cookie from the tin."
+
+ (cookie-set-buffer buffer
+
+ ;; Skip the header (or footer, if n is negative).
+ (if (< n 0)
+ (setq n (1- n))
+ (setq n (1+ n)))
+
+ (cookie-filter-hf (dll-nth cookies n))))
+
+
+
+(defun cookie-delete (buffer tin)
+ "Delete a cookie. Args: BUFFER TIN."
+
+ (cookie-set-buffer buffer
+ (if (eq cookie-last-tin tin)
+ (setq cookie-last-tin nil))
+
+ (cookie-delete-tin-internal tin)
+ (dll-delete cookies tin)))
+
+
+
+(defun cookie-delete-first (buffer)
+ "Delete first cookie and return it. Args: BUFFER.
+Returns nil if there is no cookie left."
+
+ (cookie-set-buffer buffer
+
+ ;; We have to check that we do not try to delete the footer.
+
+ (let ((tin (dll-nth cookies 1))) ;Skip the header.
+ (if (eq tin cookie-footer)
+ nil
+ (cookie-delete-tin-internal tin)
+ (cookie-tin-cookie (dll-delete cookies tin))))))
+
+
+
+(defun cookie-delete-last (buffer)
+ "Delete last cookie and return it. Args: BUFFER.
+Returns nil if there is no cookie left."
+
+ (cookie-set-buffer buffer
+
+ ;; We have to check that we do not try to delete the header.
+
+ (let ((tin (dll-nth cookies -2))) ;Skip the footer.
+ (if (eq tin cookie-header)
+ nil
+ (cookie-delete-tin-internal tin)
+ (cookie-tin-cookie (dll-delete cookies tin))))))
+
+
+
+(defun cookie-first (buffer)
+
+ "Return the first cookie in BUFFER. The cookie is not removed."
+
+ (cookie-set-buffer buffer
+ (let ((tin (cookie-filter-hf (dll-nth cookies -1))))
+ (if tin
+ (cookie-tin-cookie-safe
+ (dll-element cookies tin))))))
+
+
+(defun cookie-last (buffer)
+
+ "Return the last cookie in BUFFER. The cookie is not removed."
+
+ (cookie-set-buffer buffer
+ (let ((tin (cookie-filter-hf (dll-nth cookies -2))))
+ (if tin
+ (cookie-tin-cookie-safe
+ (dll-element cookies tin))))))
+
+
+(defun cookie-empty (buffer)
+
+ "Return true if there are no cookies in BUFFER."
+
+ (cookie-set-buffer buffer
+ (eq (dll-nth cookies 1) cookie-footer)))
+
+
+(defun cookie-length (buffer)
+
+ "Return number of cookies in BUFFER."
+
+ ;; Don't count the footer and header.
+
+ (cookie-set-buffer buffer
+ (- (dll-length cookies) 2)))
+
+
+(defun cookie-all (buffer)
+
+ "Return a list of all cookies in BUFFER."
+
+ (cookie-set-buffer buffer
+ (let (result
+ (tin (dll-nth cookies -2)))
+ (while (not (eq tin cookie-header))
+ (setq result (cons (cookie-tin-cookie (dll-element cookies tin))
+ result))
+ (setq tin (dll-previous cookies tin)))
+ result)))
+
+(defun cookie-clear (buffer)
+
+ "Remove all cookies in buffer."
+
+ (cookie-set-buffer buffer
+ (cookie-create buffer cookie-pretty-printer
+ (cookie-tin-cookie (dll-element cookies cookie-header))
+ (cookie-tin-cookie (dll-element cookies cookie-footer)))))
+
+
+
+(defun cookie-map (map-function buffer &rest map-args)
+
+ "Apply MAP-FUNCTION to all cookies in BUFFER.
+MAP-FUNCTION is applied to the first element first.
+If MAP-FUNCTION returns non-nil the cookie will be refreshed.
+
+Note that BUFFER will be current buffer when MAP-FUNCTION is called.
+
+If more than two arguments are given to cookie-map, remaining
+arguments will be passed to MAP-FUNCTION."
+
+ (cookie-set-buffer buffer
+ (let ((tin (dll-nth cookies 1))
+ result)
+
+ (while (not (eq tin cookie-footer))
+
+ (if (apply map-function
+ (cookie-tin-cookie (dll-element cookies tin))
+ map-args)
+ (cookie-refresh-tin tin))
+
+ (setq tin (dll-next cookies tin))))))
+
+
+
+(defun cookie-map-reverse (map-function buffer &rest map-args)
+
+ "Apply MAP-FUNCTION to all cookies in BUFFER.
+MAP-FUNCTION is applied to the last cookie first.
+If MAP-FUNCTION returns non-nil the cookie will be refreshed.
+
+Note that BUFFER will be current buffer when MAP-FUNCTION is called.
+
+If more than two arguments are given to cookie-map, remaining
+arguments will be passed to MAP-FUNCTION."
+
+ (cookie-set-buffer buffer
+ (let ((tin (dll-nth cookies -2))
+ result)
+
+ (while (not (eq tin cookie-header))
+
+ (if (apply map-function
+ (cookie-tin-cookie (dll-element cookies tin))
+ map-args)
+ (cookie-refresh-tin tin))
+
+ (setq tin (dll-previous cookies tin))))))
+
+
+
+(defun cookie-enter-cookies (buffer cookie-list)
+
+ "Insert all cookies in the list COOKIE-LIST last in BUFFER.
+Args: BUFFER COOKIE-LIST."
+
+ (while cookie-list
+ (cookie-enter-last buffer (car cookie-list))
+ (setq cookie-list (cdr cookie-list))))
+
+
+(defun cookie-filter (buffer predicate)
+
+ "Remove all cookies in BUFFER for which PREDICATE returns nil.
+Note that BUFFER will be current-buffer when PREDICATE is called.
+
+The PREDICATE is called with one argument, the cookie."
+
+ (cookie-set-buffer buffer
+ (let ((tin (dll-nth cookies 1))
+ next)
+ (while (not (eq tin cookie-footer))
+ (setq next (dll-next cookies tin))
+ (if (funcall predicate (cookie-tin-cookie (dll-element cookies tin)))
+ nil
+ (cookie-delete-tin-internal tin)
+ (dll-delete cookies tin))
+ (setq tin next)))))
+
+
+(defun cookie-filter-tins (buffer predicate)
+
+ "Remove all cookies in BUFFER for which PREDICATE returns nil.
+Note that BUFFER will be current-buffer when PREDICATE is called.
+
+The PREDICATE is called with one argument, the tin."
+
+ (cookie-set-buffer buffer
+ (let ((tin (dll-nth cookies 1))
+ next)
+ (while (not (eq tin cookie-footer))
+ (setq next (dll-next cookies tin))
+ (if (funcall predicate tin)
+ nil
+ (cookie-delete-tin-internal tin)
+ (dll-delete cookies tin))
+ (setq tin next)))))
+
+(defun cookie-pos-before-middle-p (pos tin1 tin2)
+
+ "Return true if POS is in the first half of the region defined by TIN1 and
+TIN2."
+
+ (< pos (/ (+ (cookie-tin-start-marker (dll-element cookeis tin1))
+ (cookie-tin-start-marker (dll-element cookeis tin2)))
+ 2)))
+
+
+(defun cookie-get-selection (buffer pos &optional guess force-guess)
+
+ "Return the tin the POS is within.
+Args: BUFFER POS &optional GUESS FORCE-GUESS.
+GUESS should be a tin that it is likely that POS is near. If FORCE-GUESS
+is non-nil GUESS is always used as a first guess, otherwise the first
+guess is the first tin, last tin, or GUESS, whichever is nearest to
+pos in the BUFFER.
+
+If pos points within the header, the first cookie is returned.
+If pos points within the footer, the last cookie is returned.
+Nil is returned if there is no cookie.
+
+It is often good to specify cookie-last-tin as GUESS, but remember
+that cookie-last-tin is buffer local in all buffers that cookie
+operates on."
+
+ (cookie-set-buffer buffer
+
+ (cond
+ ; No cookies present?
+ ((eq (dll-nth cookies 1) (dll-nth cookies -1))
+ nil)
+
+ ; Before first cookie?
+ ((< pos (cookie-tin-start-marker
+ (dll-element cookies (dll-nth cookies 1))))
+ (dll-nth cookies 1))
+
+ ; After last cookie?
+ ((>= pos (cookie-tin-start-marker (dll-last cookies)))
+ (dll-nth cookies -2))
+
+ ; We now now that pos is within a cookie.
+ (t
+ ; Make an educated guess about which of the three known
+ ; cookies (the first, the last, or GUESS) is nearest.
+ (setq
+ guess
+ (cond
+ (force-guess guess)
+ (guess
+ (cond
+ ;; Closest to first cookie?
+ ((cookie-pos-before-middle-p
+ pos guess
+ (dll-nth cookies 1))
+ (dll-nth cookies 1))
+ ;; Closest to GUESS?
+ ((cookie-pos-before-middle-p
+ pos guess
+ cookie-footer)
+ guess)
+ ;; Closest to last cookie.
+ (t (dll-previous cookies cookie-footer))))
+ (t
+ ;; No guess given.
+ (cond
+ ;; First half?
+ ((cookie-pos-before-middle-p
+ pos (dll-nth cookies 1)
+ cookie-footer)
+ (dll-nth cookies 1))
+ (t (dll-previous cookies cookie-footer))))))
+
+ ;; GUESS is now a "best guess".
+
+ ;; Find the correct cookie. First determine in which direction
+ ;; it lies, and then move in that direction until it is found.
+
+ (cond
+ ;; Is pos after the guess?
+ ((>= pos (cookie-tin-start-marker (dll-element cookiess guess)))
+
+ ;; Loop until we are exactly one cookie too far down...
+ (while (>= pos (cookie-tin-start-marker (dll-element cookiess guess)))
+ (setq guess (dll-next cookies guess)))
+
+ ;; ...and return the previous cookie.
+ (dll-previous cookies guess))
+
+ ;; Pos is before guess
+ (t
+
+ (while (< pos (cookie-tin-start-marker (dll-element cookiess guess)))
+ (setq guess (dll-previous cookies guess)))
+
+ guess))))))
+
+
+(defun cookie-start-marker (buffer tin)
+
+ "Return start-position of a cookie in BUFFER.
+Args: BUFFER TIN.
+The marker that is returned should not be modified in any way,
+and is only valid until the contents of the cookie buffer changes."
+
+ (cookie-set-buffer buffer
+ (cookie-tin-start-marker (dll-element cookies tin))))
+
+
+(defun cookie-end-marker (buffer tin)
+
+ "Return end-position of a cookie in BUFFER.
+Args: BUFFER TIN.
+The marker that is returned should not be modified in any way,
+and is only valid until the contents of the cookie buffer changes."
+
+ (cookie-set-buffer buffer
+ (cookie-tin-start-marker
+ (dll-element cookies (dll-next cookies tin)))))
+
+
+
+(defun cookie-refresh (buffer)
+
+ "Refresh all cookies in BUFFER.
+Cookie-pretty-printer will be called for all cookies and the new result
+displayed.
+
+See also cookie-invalidate-tins."
+
+ (cookie-set-buffer buffer
+
+ (erase-buffer)
+
+ (set-marker (cookie-tin-start-marker (dll-element cookies cookie-header))
+ (point) buffer)
+ (insert (cookie-tin-cookie (dll-element cookies cookie-header)))
+ (insert "\n")
+
+ (let ((tin (dll-nth cookies 1)))
+ (while (not (eq tin cookie-footer))
+
+ (set-marker (cookie-tin-start-marker (dll-element cookies tin))
+ (point) buffer)
+ (insert
+ (funcall cookie-pretty-printer
+ (cookie-tin-cookie (dll-element cookies tin))))
+ (insert "\n")
+ (setq tin (dll-next cookies tin))))
+
+ (set-marker (cookie-tin-start-marker (dll-element cookies cookie-footer))
+ (point) buffer)
+ (insert (cookie-tin-cookie (dll-element cookies cookie-footer)))
+ (insert "\n")))
+
+
+(defun cookie-invalidate-tins (buffer &rest tins)
+
+ "Refresh some cookies.
+Args: BUFFER &rest TINS."
+
+ (cookie-set-buffer buffer
+
+ (while tins
+ (cookie-refresh-tin (car tins))
+ (setq tins (cdr tins)))))
+
+
+;;; Cookie movement commands.
+
+(defun cookie-set-goal-column (buffer goal)
+ "Set goal-column for BUFFER.
+Args: BUFFER GOAL.
+goal-column is made buffer-local."
+ (cookie-set-buffer buffer
+ (make-local-variable 'goal-column)
+ (setq goal-column goal)))
+
+
+(defun cookie-previous-cookie (buffer pos arg)
+ "Move point to the ARGth previous cookie.
+Don't move if we are at the first cookie.
+ARG is the prefix argument when called interactively.
+Args: BUFFER POS ARG.
+Sets cookie-last-tin to the cookie we move to."
+
+ (interactive (list (current-buffer) (point)
+ (prefix-numeric-value current-prefix-arg)))
+
+ (cookie-set-buffer buffer
+ (setq cookie-last-tin
+ (cookie-get-selection buffer pos cookie-last-tin))
+
+ (while (and cookie-last-tin (> arg 0))
+ (setq arg (1- arg))
+ (setq cookie-last-tin
+ (dll-previous cookies cookie-last-tin)))
+
+ ;; Never step above the first cookie.
+
+ (if (null (cookie-filter-hf cookie-last-tin))
+ (setq cookie-last-tin (dll-nth cookies 1)))
+
+ (goto-char
+ (cookie-tin-start-marker
+ (dll-element cookies cookie-last-tin)))
+
+ (if goal-column
+ (move-to-column goal-column))))
+
+
+
+(defun cookie-next-cookie (buffer pos arg)
+ "Move point to the ARGth next cookie.
+Don't move if we are at the last cookie.
+ARG is the prefix argument when called interactively.
+Args: BUFFER POS ARG.
+Sets cookie-last-tin to the cookie we move to."
+
+ (interactive (list (current-buffer) (point)
+ (prefix-numeric-value current-prefix-arg)))
+
+ (cookie-set-buffer buffer
+ (setq cookie-last-tin
+ (cookie-get-selection buffer pos cookie-last-tin))
+
+ (while (and cookie-last-tin (> arg 0))
+ (setq arg (1- arg))
+ (setq cookie-last-tin
+ (dll-next cookies cookie-last-tin)))
+
+ (if (null (cookie-filter-hf cookie-last-tin))
+ (setq cookie-last-tin (dll-nth cookies -2)))
+
+ (goto-char
+ (cookie-tin-start-marker
+ (dll-element cookies cookie-last-tin)))
+
+ (if goal-column
+ (move-to-column goal-column))))
+
+
+(defun cookie-collect-tins (buffer predicate &rest predicate-args)
+
+ "Return a list of all tins in BUFFER whose cookie PREDICATE
+returns true for.
+PREDICATE is a function that takes a cookie as its argument.
+The tins on the returned list will appear in the same order
+as in the buffer. You should not rely on in which order PREDICATE
+is called. Note that BUFFER is current-buffer when PREDICATE
+is called. (If you call cookie-collect with another buffer set
+as current-buffer and need to access buffer-local variables
+from that buffer within PREDICATE you must send them via
+PREDICATE-ARGS).
+
+If more than two arguments are given to cookie-collect the remaining
+arguments will be passed to PREDICATE.
+
+Use cookie-cookie to get the cookie from the tin."
+
+ (cookie-set-buffer buffer
+ (let ((tin (dll-nth cookies -2))
+ result)
+
+ (while (not (eq tin cookie-header))
+
+ (if (apply predicate
+ (cookie-tin-cookie (dll-element cookies tin))
+ predicate-args)
+ (setq result (cons tin result)))
+
+ (setq tin (dll-previous cookies tin)))
+ result)))
+
+
+(defun cookie-collect-cookies (buffer predicate &rest predicate-args)
+
+ "Return a list of all cookies in BUFFER that PREDICATE
+returns true for.
+PREDICATE is a function that takes a cookie as its argument.
+The cookie on the returned list will appear in the same order
+as in the buffer. You should not rely on in which order PREDICATE
+is called. Note that BUFFER is current-buffer when PREDICATE
+is called. (If you call cookie-collect with another buffer set
+as current-buffer and need to access buffer-local variables
+from that buffer within PREDICATE you must send them via
+PREDICATE-ARGS).
+
+If more than two arguments are given to cookie-collect the remaining
+arguments will be passed to PREDICATE."
+
+ (cookie-set-buffer buffer
+ (let ((tin (dll-nth cookies -2))
+ result)
+
+ (while (not (eq tin cookie-header))
+
+ (if (apply predicate
+ (cookie-tin-cookie (dll-element cookies tin))
+ predicate-args)
+ (setq result (cons (cookie-tin-cookie (dll-element cookies tin))
+ result)))
+
+ (setq tin (dll-previous cookies tin)))
+ result)))
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll-debug.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll-debug.el
new file mode 100644
index 000000000000..733ff86f46c0
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll-debug.el
@@ -0,0 +1,298 @@
+;;; elib-dll-debug -- A slow implementation of elib-dll for debugging.
+;;; elib-dll-debug.el,v 1.2 1992/04/07 20:49:13 berliner Exp
+;;; Copyright (C) 1991,1992 Per Cederqvist
+;;;
+;;; This program is free software; you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 2 of the License, or
+;;; (at your option) any later version.
+;;;
+;;; This program is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with this program; if not, write to the Free Software
+;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+;;; This is a plug-in replacement for elib-dll.el. It is dreadfully
+;;; slow, but it facilitates debugging. Don't trust the comments in
+;;; this file too much.
+(provide 'elib-dll)
+
+;;;
+;;; A doubly linked list consists of one cons cell which holds the tag
+;;; 'DL-LIST in the car cell and the list in the cdr
+;;; cell. The doubly linked list is implemented as a normal list. You
+;;; should use elib-dll.el and not this package in debugged code. This
+;;; package is not written for speed...
+;;;
+
+;;; ================================================================
+;;; Internal functions for use in the doubly linked list package
+
+(defun dll-get-dummy-node (dll)
+
+ ;; Return the dummy node. INTERNAL USE ONLY.
+ dll)
+
+(defun dll-list-nodes (dll)
+
+ ;; Return a list of all nodes in DLL. INTERNAL USE ONLY.
+
+ (cdr dll))
+
+(defun dll-set-from-node-list (dll list)
+
+ ;; Set the contents of DLL to the nodes in LIST.
+ ;; INTERNAL USE ONLY.
+
+ (setcdr dll list))
+
+(defun dll-get-node-before (dll node)
+ ;; Return the node in DLL that points to NODE. Use
+ ;; (dll-get-node-before some-list nil) to get the last node.
+ ;; INTERNAL USE ONLY.
+ (while (and dll (not (eq (cdr dll) node)))
+ (setq dll (cdr dll)))
+ (if (not dll)
+ (error "Node not on list"))
+ dll)
+
+(defmacro dll-insert-after (node element)
+ (let ((node-v (make-symbol "node"))
+ (element-v (make-symbol "element")))
+ (` (let (((, node-v) (, node))
+ ((, element-v) (, element)))
+ (setcdr (, node-v) (cons (, element-v) (cdr (, node-v))))))))
+
+;;; ===================================================================
+;;; The public functions which operate on doubly linked lists.
+
+(defmacro dll-element (dll node)
+
+ "Get the element of a NODE in a doubly linked list DLL.
+Args: DLL NODE."
+
+ (` (car (, node))))
+
+
+(defun dll-create ()
+ "Create an empty doubly linked list."
+ (cons 'DL-LIST nil))
+
+
+(defun dll-p (object)
+ "Return t if OBJECT is a doubly linked list, otherwise return nil."
+ (eq (car-safe object) 'DL-LIST))
+
+
+(defun dll-enter-first (dll element)
+ "Add an element first on a doubly linked list.
+Args: DLL ELEMENT."
+ (setcdr dll (cons element (cdr dll))))
+
+
+(defun dll-enter-last (dll element)
+ "Add an element last on a doubly linked list.
+Args: DLL ELEMENT."
+ (dll-insert-after (dll-get-node-before dll nil) element))
+
+
+(defun dll-enter-after (dll node element)
+ "In the doubly linked list DLL, insert a node containing ELEMENT after NODE.
+Args: DLL NODE ELEMENT."
+
+ (dll-get-node-before dll node)
+ (dll-insert-after node element))
+
+
+(defun dll-enter-before (dll node element)
+ "In the doubly linked list DLL, insert a node containing ELEMENT before NODE.
+Args: DLL NODE ELEMENT."
+
+ (dll-insert-after (dll-get-node-before dll node) element))
+
+
+
+(defun dll-next (dll node)
+ "Return the node after NODE, or nil if NODE is the last node.
+Args: DLL NODE."
+
+ (dll-get-node-before dll node)
+ (cdr node))
+
+
+(defun dll-previous (dll node)
+ "Return the node before NODE, or nil if NODE is the first node.
+Args: DLL NODE."
+
+ (dll-get-node-before dll node))
+
+
+(defun dll-delete (dll node)
+
+ "Delete NODE from the doubly linked list DLL.
+Args: DLL NODE. Return the element of node."
+
+ ;; This is a no-op when applied to the dummy node. This will return
+ ;; nil if applied to the dummy node since it always contains nil.
+
+ (setcdr (dll-get-node-before dll node) (cdr node)))
+
+
+(defun dll-delete-first (dll)
+
+ "Delete the first NODE from the doubly linked list DLL.
+Return the element. Args: DLL. Returns nil if the DLL was empty."
+
+ ;; Relies on the fact that dll-delete does nothing and
+ ;; returns nil if given the dummy node.
+
+ (setcdr dll (cdr (cdr dll))))
+
+
+(defun dll-delete-last (dll)
+
+ "Delete the last NODE from the doubly linked list DLL.
+Return the element. Args: DLL. Returns nil if the DLL was empty."
+
+ ;; Relies on the fact that dll-delete does nothing and
+ ;; returns nil if given the dummy node.
+
+ (setcdr dll (dll-get-node-before dll nil) nil))
+
+
+(defun dll-first (dll)
+
+ "Return the first element on the doubly linked list DLL.
+Return nil if the list is empty. The element is not removed."
+
+ (car (cdr dll)))
+
+
+
+
+(defun dll-last (dll)
+
+ "Return the last element on the doubly linked list DLL.
+Return nil if the list is empty. The element is not removed."
+
+ (car (dll-get-node-before dll nil)))
+
+
+
+(defun dll-nth (dll n)
+
+ "Return the Nth node from the doubly linked list DLL.
+ Args: DLL N
+N counts from zero. If DLL is not that long, nil is returned.
+If N is negative, return the -(N+1)th last element.
+Thus, (dll-nth dll 0) returns the first node,
+and (dll-nth dll -1) returns the last node."
+
+ ;; Branch 0 ("follow left pointer") is used when n is negative.
+ ;; Branch 1 ("follow right pointer") is used otherwise.
+
+ (if (>= n 0)
+ (nthcdr n (cdr dll))
+ (unwind-protect
+ (progn (setcdr dll (nreverse (cdr dll)))
+ (nthcdr (- n) dll))
+ (setcdr dll (nreverse (cdr dll))))))
+
+(defun dll-empty (dll)
+
+ "Return t if the doubly linked list DLL is empty, nil otherwise"
+
+ (not (cdr dll)))
+
+(defun dll-length (dll)
+
+ "Returns the number of elements in the doubly linked list DLL."
+
+ (length (cdr dll)))
+
+
+
+(defun dll-copy (dll &optional element-copy-fnc)
+
+ "Return a copy of the doubly linked list DLL.
+If optional second argument ELEMENT-COPY-FNC is non-nil it should be
+a function that takes one argument, an element, and returns a copy of it.
+If ELEMENT-COPY-FNC is not given the elements are not copied."
+
+ (if element-copy-fnc
+ (cons 'DL-LIST (mapcar element-copy-fnc (cdr dll)))
+ (copy-sequence dll)))
+
+
+(defun dll-all (dll)
+
+ "Return all elements on the double linked list DLL as an ordinary list."
+
+ (cdr dll))
+
+
+(defun dll-clear (dll)
+
+ "Clear the doubly linked list DLL, i.e. make it completely empty."
+
+ (setcdr dll nil))
+
+
+(defun dll-map (map-function dll)
+
+ "Apply MAP-FUNCTION to all elements in the doubly linked list DLL.
+The function is applied to the first element first."
+
+ (mapcar map-function (cdr dll)))
+
+
+(defun dll-map-reverse (map-function dll)
+
+ "Apply MAP-FUNCTION to all elements in the doubly linked list DLL.
+The function is applied to the last element first."
+
+ (unwind-protect
+ (setcdr dll (nreverse (cdr dll)))
+ (mapcar map-function (cdr dll))
+ (setcdr dll (nreverse (cdr dll)))))
+
+
+(defun dll-create-from-list (list)
+
+ "Given an elisp LIST create a doubly linked list with the same elements."
+
+ (cons 'DL-LIST list))
+
+
+
+(defun dll-sort (dll predicate)
+
+ "Sort the doubly linked list DLL, stably, comparing elements using PREDICATE.
+Returns the sorted list. DLL is modified by side effects.
+PREDICATE is called with two elements of DLL, and should return T
+if the first element is \"less\" than the second."
+
+ (setcdr dll (sort (cdr dll) predicate))
+ dll)
+
+
+(defun dll-filter (dll predicate)
+
+ "Remove all elements in the doubly linked list DLL for which PREDICATE
+return nil."
+
+ (let* ((prev dll)
+ (node (cdr dll)))
+
+ (while node
+ (cond
+ ((funcall predicate (car node))
+ (setq prev node))
+ (t
+ (setcdr prev (cdr node))))
+ (setq node (cdr node)))))
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll.el
new file mode 100644
index 000000000000..855bd19e8ee0
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll.el
@@ -0,0 +1,386 @@
+;;; elib-dll.el,v 1.2 1992/04/07 20:49:15 berliner Exp
+;;; elib-dll.el -- Some primitives for Doubly linked lists.
+;;; Copyright (C) 1991, 1992 Per Cederqvist
+;;;
+;;; This program is free software; you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 2 of the License, or
+;;; (at your option) any later version.
+;;;
+;;; This program is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with this program; if not, write to the Free Software
+;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Mail bug reports to ceder@lysator.liu.se.
+
+(require 'elib-node)
+(provide 'elib-dll)
+
+;;;
+;;; A doubly linked list consists of one cons cell which holds the tag
+;;; 'DL-LIST in the car cell and a pointer to a dummy node in the cdr
+;;; cell. The doubly linked list is implemented as a circular list
+;;; with the dummy node first and last. The dummy node is recognized
+;;; by comparing it to the node which the cdr of the cons cell points
+;;; to.
+;;;
+
+;;; ================================================================
+;;; Internal functions for use in the doubly linked list package
+
+(defun dll-get-dummy-node (dll)
+
+ ;; Return the dummy node. INTERNAL USE ONLY.
+ (cdr dll))
+
+(defun dll-list-nodes (dll)
+
+ ;; Return a list of all nodes in DLL. INTERNAL USE ONLY.
+
+ (let* ((result nil)
+ (dummy (dll-get-dummy-node dll))
+ (node (elib-node-left dummy)))
+
+ (while (not (eq node dummy))
+ (setq result (cons node result))
+ (setq node (elib-node-left node)))
+
+ result))
+
+(defun dll-set-from-node-list (dll list)
+
+ ;; Set the contents of DLL to the nodes in LIST.
+ ;; INTERNAL USE ONLY.
+
+ (dll-clear dll)
+ (let* ((dummy (dll-get-dummy-node dll))
+ (left dummy))
+ (while list
+ (elib-node-set-left (car list) left)
+ (elib-node-set-right left (car list))
+ (setq left (car list))
+ (setq list (cdr list)))
+
+ (elib-node-set-right left dummy)
+ (elib-node-set-left dummy left)))
+
+
+;;; ===================================================================
+;;; The public functions which operate on doubly linked lists.
+
+(defmacro dll-element (dll node)
+
+ "Get the element of a NODE in a doubly linked list DLL.
+Args: DLL NODE."
+
+ (` (elib-node-data (, node))))
+
+
+(defun dll-create ()
+ "Create an empty doubly linked list."
+ (let ((dummy-node (elib-node-create nil nil nil)))
+ (elib-node-set-right dummy-node dummy-node)
+ (elib-node-set-left dummy-node dummy-node)
+ (cons 'DL-LIST dummy-node)))
+
+(defun dll-p (object)
+ "Return t if OBJECT is a doubly linked list, otherwise return nil."
+ (eq (car-safe object) 'DL-LIST))
+
+(defun dll-enter-first (dll element)
+ "Add an element first on a doubly linked list.
+Args: DLL ELEMENT."
+ (dll-enter-after
+ dll
+ (dll-get-dummy-node dll)
+ element))
+
+
+(defun dll-enter-last (dll element)
+ "Add an element last on a doubly linked list.
+Args: DLL ELEMENT."
+ (dll-enter-before
+ dll
+ (dll-get-dummy-node dll)
+ element))
+
+
+(defun dll-enter-after (dll node element)
+ "In the doubly linked list DLL, insert a node containing ELEMENT after NODE.
+Args: DLL NODE ELEMENT."
+
+ (let ((new-node (elib-node-create
+ node (elib-node-right node)
+ element)))
+ (elib-node-set-left (elib-node-right node) new-node)
+ (elib-node-set-right node new-node)))
+
+
+(defun dll-enter-before (dll node element)
+ "In the doubly linked list DLL, insert a node containing ELEMENT before NODE.
+Args: DLL NODE ELEMENT."
+
+ (let ((new-node (elib-node-create
+ (elib-node-left node) node
+ element)))
+ (elib-node-set-right (elib-node-left node) new-node)
+ (elib-node-set-left node new-node)))
+
+
+
+(defun dll-next (dll node)
+ "Return the node after NODE, or nil if NODE is the last node.
+Args: DLL NODE."
+
+ (if (eq (elib-node-right node) (dll-get-dummy-node dll))
+ nil
+ (elib-node-right node)))
+
+
+(defun dll-previous (dll node)
+ "Return the node before NODE, or nil if NODE is the first node.
+Args: DLL NODE."
+
+ (if (eq (elib-node-left node) (dll-get-dummy-node dll))
+ nil
+ (elib-node-left node)))
+
+
+(defun dll-delete (dll node)
+
+ "Delete NODE from the doubly linked list DLL.
+Args: DLL NODE. Return the element of node."
+
+ ;; This is a no-op when applied to the dummy node. This will return
+ ;; nil if applied to the dummy node since it always contains nil.
+
+ (elib-node-set-right (elib-node-left node) (elib-node-right node))
+ (elib-node-set-left (elib-node-right node) (elib-node-left node))
+ (dll-element dll node))
+
+
+
+(defun dll-delete-first (dll)
+
+ "Delete the first NODE from the doubly linked list DLL.
+Return the element. Args: DLL. Returns nil if the DLL was empty."
+
+ ;; Relies on the fact that dll-delete does nothing and
+ ;; returns nil if given the dummy node.
+
+ (dll-delete dll (elib-node-right (dll-get-dummy-node dll))))
+
+
+(defun dll-delete-last (dll)
+
+ "Delete the last NODE from the doubly linked list DLL.
+Return the element. Args: DLL. Returns nil if the DLL was empty."
+
+ ;; Relies on the fact that dll-delete does nothing and
+ ;; returns nil if given the dummy node.
+
+ (dll-delete dll (elib-node-left (dll-get-dummy-node dll))))
+
+
+(defun dll-first (dll)
+
+ "Return the first element on the doubly linked list DLL.
+Return nil if the list is empty. The element is not removed."
+
+ (if (eq (elib-node-right (dll-get-dummy-node dll))
+ (dll-get-dummy-node dll))
+ nil
+ (elib-node-data (elib-node-right (dll-get-dummy-node dll)))))
+
+
+
+
+(defun dll-last (dll)
+
+ "Return the last element on the doubly linked list DLL.
+Return nil if the list is empty. The element is not removed."
+
+ (if (eq (elib-node-left (dll-get-dummy-node dll))
+ (dll-get-dummy-node dll))
+ nil
+ (elib-node-data (elib-node-left (dll-get-dummy-node dll)))))
+
+
+
+(defun dll-nth (dll n)
+
+ "Return the Nth node from the doubly linked list DLL.
+ Args: DLL N
+N counts from zero. If DLL is not that long, nil is returned.
+If N is negative, return the -(N+1)th last element.
+Thus, (dll-nth dll 0) returns the first node,
+and (dll-nth dll -1) returns the last node."
+
+ ;; Branch 0 ("follow left pointer") is used when n is negative.
+ ;; Branch 1 ("follow right pointer") is used otherwise.
+
+ (let* ((dummy (dll-get-dummy-node dll))
+ (branch (if (< n 0) 0 1))
+ (node (elib-node-branch dummy branch)))
+
+ (if (< n 0)
+ (setq n (- -1 n)))
+
+ (while (and (not (eq dummy node))
+ (> n 0))
+ (setq node (elib-node-branch node branch))
+ (setq n (1- n)))
+
+ (if (eq dummy node)
+ nil
+ node)))
+
+
+(defun dll-empty (dll)
+
+ "Return t if the doubly linked list DLL is empty, nil otherwise"
+
+ (eq (elib-node-left (dll-get-dummy-node dll))
+ (dll-get-dummy-node dll)))
+
+(defun dll-length (dll)
+
+ "Returns the number of elements in the doubly linked list DLL."
+
+ (let* ((dummy (dll-get-dummy-node dll))
+ (node (elib-node-right dummy))
+ (n 0))
+
+ (while (not (eq node dummy))
+ (setq node (elib-node-right node))
+ (setq n (1+ n)))
+
+ n))
+
+
+
+(defun dll-copy (dll &optional element-copy-fnc)
+
+ "Return a copy of the doubly linked list DLL.
+If optional second argument ELEMENT-COPY-FNC is non-nil it should be
+a function that takes one argument, an element, and returns a copy of it.
+If ELEMENT-COPY-FNC is not given the elements are not copied."
+
+ (let ((result (dll-create))
+ (node (dll-nth dll 0)))
+ (if element-copy-fnc
+
+ ;; Copy the elements with the user-supplied function.
+ (while node
+ (dll-enter-last result
+ (funcall element-copy-fnc
+ (dll-element dll node)))
+ (setq node (dll-next dll node)))
+
+ ;; Don't try to copy the elements - they might be
+ ;; circular lists, or anything at all...
+ (while node
+ (dll-enter-last result (dll-element dll node))
+ (setq node (dll-next dll node))))
+
+ result))
+
+
+
+(defun dll-all (dll)
+
+ "Return all elements on the double linked list DLL as an ordinary list."
+
+ (let* ((result nil)
+ (dummy (dll-get-dummy-node dll))
+ (node (elib-node-left dummy)))
+
+ (while (not (eq node dummy))
+ (setq result (cons (dll-element dll node) result))
+ (setq node (elib-node-left node)))
+
+ result))
+
+
+(defun dll-clear (dll)
+
+ "Clear the doubly linked list DLL, i.e. make it completely empty."
+
+ (elib-node-set-left (dll-get-dummy-node dll) (dll-get-dummy-node dll))
+ (elib-node-set-right (dll-get-dummy-node dll) (dll-get-dummy-node dll)))
+
+
+(defun dll-map (map-function dll)
+
+ "Apply MAP-FUNCTION to all elements in the doubly linked list DLL.
+The function is applied to the first element first."
+
+ (let* ((dummy (dll-get-dummy-node dll))
+ (node (elib-node-right dummy)))
+
+ (while (not (eq node dummy))
+ (funcall map-function (dll-element dll node))
+ (setq node (elib-node-right node)))))
+
+
+(defun dll-map-reverse (map-function dll)
+
+ "Apply MAP-FUNCTION to all elements in the doubly linked list DLL.
+The function is applied to the last element first."
+
+ (let* ((dummy (dll-get-dummy-node dll))
+ (node (elib-node-left dummy)))
+
+ (while (not (eq node dummy))
+ (funcall map-function (dll-element dll node))
+ (setq node (elib-node-left node)))))
+
+
+(defun dll-create-from-list (list)
+
+ "Given an elisp LIST create a doubly linked list with the same elements."
+
+ (let ((dll (dll-create)))
+ (while list
+ (dll-enter-last dll (car list))
+ (setq list (cdr list)))
+ dll))
+
+
+
+(defun dll-sort (dll predicate)
+
+ "Sort the doubly linked list DLL, stably, comparing elements using PREDICATE.
+Returns the sorted list. DLL is modified by side effects.
+PREDICATE is called with two elements of DLL, and should return T
+if the first element is \"less\" than the second."
+
+ (dll-set-from-node-list
+ dll (sort (dll-list-nodes dll)
+ (function (lambda (x1 x2)
+ (funcall predicate
+ (dll-element dll x1)
+ (dll-element dll x2))))))
+ dll)
+
+
+(defun dll-filter (dll predicate)
+
+ "Remove all elements in the doubly linked list DLL for which PREDICATE
+return nil."
+
+ (let* ((dummy (dll-get-dummy-node dll))
+ (node (elib-node-right dummy))
+ next)
+
+ (while (not (eq node dummy))
+ (setq next (elib-node-right node))
+ (if (funcall predicate (dll-element dll node))
+ nil
+ (dll-delete dll node))
+ (setq node next))))
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-node.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-node.el
new file mode 100644
index 000000000000..6c476a35ef3d
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-node.el
@@ -0,0 +1,89 @@
+;;;; elib-node.el,v 1.2 1992/04/07 20:49:16 berliner Exp
+;;;; This file implements the nodes used in binary trees and
+;;;; doubly linked lists
+;;;;
+;;;; Copyright (C) 1991 Inge Wallin
+;;;;
+;;;; This file is part of the GNU Emacs lisp library, Elib.
+;;;;
+;;;; GNU Elib is free software; you can redistribute it and/or modify
+;;;; it under the terms of the GNU General Public License as published by
+;;;; the Free Software Foundation; either version 1, or (at your option)
+;;;; any later version.
+;;;;
+;;;; GNU Elib is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;;; GNU General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU General Public License
+;;;; along with GNU Emacs; see the file COPYING. If not, write to
+;;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+;;;;
+;;;; Author: Inge Wallin
+;;;;
+
+;;;
+;;; A node is implemented as an array with three elements, using
+;;; (elt node 0) as the left pointer
+;;; (elt node 1) as the right pointer
+;;; (elt node 2) as the data
+;;;
+;;; Some types of trees, e.g. AVL trees, need bigger nodes, but
+;;; as long as the first three parts are the left pointer, the
+;;; right pointer and the data field, these macros can be used.
+;;;
+
+
+(provide 'elib-node)
+
+
+(defmacro elib-node-create (left right data)
+ "Create a tree node from LEFT, RIGHT and DATA."
+ (` (vector (, left) (, right) (, data))))
+
+
+(defmacro elib-node-left (node)
+ "Return the left pointer of NODE."
+ (` (aref (, node) 0)))
+
+
+(defmacro elib-node-right (node)
+ "Return the right pointer of NODE."
+ (` (aref (, node) 1)))
+
+
+(defmacro elib-node-data (node)
+ "Return the data of NODE."
+ (` (aref (, node) 2)))
+
+
+(defmacro elib-node-set-left (node newleft)
+ "Set the left pointer of NODE to NEWLEFT."
+ (` (aset (, node) 0 (, newleft))))
+
+
+(defmacro elib-node-set-right (node newright)
+ "Set the right pointer of NODE to NEWRIGHT."
+ (` (aset (, node) 1 (, newright))))
+
+
+(defmacro elib-node-set-data (node newdata)
+ "Set the data of NODE to NEWDATA."
+ (` (aset (, node) 2 (, newdata))))
+
+
+
+(defmacro elib-node-branch (node branch)
+ "Get value of a branch of a node.
+NODE is the node, and BRANCH is the branch.
+0 for left pointer, 1 for right pointer and 2 for the data."
+ (` (aref (, node) (, branch))))
+
+
+(defmacro elib-node-set-branch (node branch newval)
+ "Set value of a branch of a node.
+NODE is the node, and BRANCH is the branch.
+0 for left pointer, 1 for the right pointer and 2 for the data.
+NEWVAL is new value of the branch."
+ (` (aset (, node) (, branch) (, newval))))
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-startup.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-startup.el
new file mode 100644
index 000000000000..27bb57cddd84
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-startup.el
@@ -0,0 +1,6 @@
+;;; pcl-cvs-startup.el,v 1.2 1992/04/07 20:49:17 berliner Exp
+(autoload 'cvs-update "pcl-cvs"
+ "Run a 'cvs update' in the current working directory. Feed the
+output to a *cvs* buffer and run cvs-mode on it.
+If optional prefix argument LOCAL is non-nil, 'cvs update -l' is run."
+ t)
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.el
new file mode 100644
index 000000000000..99da3695ad7d
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.el
@@ -0,0 +1,1476 @@
+;;; pcl-cvs.el,v 1.2 1992/04/07 20:49:19 berliner Exp
+;;; pcl-cvs.el -- A Front-end to CVS 1.3 or later. Release 1.02.
+;;; Copyright (C) 1991, 1992 Per Cederqvist
+;;;
+;;; This program is free software; you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 2 of the License, or
+;;; (at your option) any later version.
+;;;
+;;; This program is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with this program; if not, write to the Free Software
+;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;;; See below for installation instructions.
+;;;;
+;;;; There is an TeXinfo file that describes this package. The GNU
+;;;; General Public License is included in that file. You should read
+;;;; it to get the most from this package.
+
+;;; Don't try to use this with CVS 1.2 or earlier. It won't work. Get
+;;; CVS 1.3.
+
+;;; Mail questions and bug reports to ceder@lysator.liu.se.
+
+(require 'cookie)
+(provide 'pcl-cvs)
+
+;;; -------------------------------------------------------
+;;; START OF THINGS TO CHECK WHEN INSTALLING
+
+(defvar cvs-program "/usr/gnu/bin/cvs"
+ "*Full path to the cvs executable.")
+
+(defvar cvs-diff-program "/usr/gnu/bin/diff"
+ "*Full path to the diff program.")
+
+(defvar cvs-rm-program "/usr/gnu/bin/rm"
+ "*Full path to the rm program. Typically /bin/rm.")
+
+;; Uncomment the following line if you are running on 18.57 or earlier.
+;(setq delete-exited-processes nil)
+;; Emacs version 18.57 and earlier is likely to crash if
+;; delete-exited-processes is t, since the sentinel uses lots of
+;; memory, and 18.57 forgets to GCPROT a variable if
+;; delete-exited-processes is t.
+
+;;; END OF THINGS TO CHECK WHEN INSTALLING
+;;; --------------------------------------------------------
+
+(defvar cvs-bakprefix ".#"
+ "The prefix that CVS prepends to files when rcsmerge'ing.")
+
+(defvar cvs-erase-input-buffer nil
+ "*Non-nil if input buffers should be cleared before asking for new info.")
+
+(defvar cvs-auto-remove-handled nil
+ "*Non-nil if cvs-remove-handled should be called automatically.
+If this is set to any non-nil value entries that does not need to be
+checked in will be removed from the *cvs* buffer after every cvs-commit
+command.")
+
+(defconst cvs-cursor-column 14
+ "Column to position cursor in in cvs-mode.
+Column 0 is left-most column.")
+
+(defvar cvs-mode-map nil
+ "Keymap for the cvs mode.")
+
+(defvar cvs-edit-mode-map nil
+ "Keymap for the cvs edit mode (used when editing cvs log messages).")
+
+(defvar cvs-buffer-name "*cvs*"
+ "Name of the cvs buffer.")
+
+(defvar cvs-commit-prompt-buffer "*cvs-commit-message*"
+ "Name of buffer in which the user is prompted for a log message when
+committing files.")
+
+(defvar cvs-temp-buffer-name "*cvs-tmp*"
+ "*Name of the cvs temporary buffer.
+Output from cvs is placed here by synchronous commands.")
+
+(defvar cvs-cvs-diff-flags nil
+ "*List of strings to use as flags to pass to ``cvs diff''.
+Used by cvs-diff-cvs.
+Set this to '("-u") to get a Unidiff format, or '("-c") to get context diffs.")
+
+(defvar cvs-status-flags nil
+ "*List of strings to pass to ``cvs status''.")
+
+(defvar cvs-log-flags nil
+ "*List of strings to pass to ``cvs log''.")
+
+(defvar cvs-diff-flags nil
+ "*List of strings to use as flags to pass to ``diff''.
+Do not confuse with cvs-cvs-diff-flags. Used by cvs-diff-backup.")
+
+(defvar cvs-buffers-to-delete nil
+ "List of temporary buffers that should be discarded as soon as possible.
+Due to a bug in emacs 18.57 the sentinel can't discard them reliably.")
+
+;; You are NOT allowed to disable this message by default. However, you
+;; are encouraged to inform your users that by adding
+;; (setq cvs-inhibit-copyright-message t)
+;; to their .emacs they can get rid of it. Just don't add that line
+;; to your default.el!
+(defvar cvs-inhibit-copyright-message nil
+ "*Don't display a Copyright message in the ``*cvs*'' buffer.")
+
+(defvar cvs-startup-message
+ (if cvs-inhibit-copyright-message
+ "PCL-CVS release 1.02"
+ "PCL-CVS release 1.02. Copyright (C) 1992 Per Cederqvist
+Pcl-cvs comes with absolutely no warranty; for details consult the manual.
+This is free software, and you are welcome to redistribute it under certain
+conditions; again, consult the TeXinfo manual for details.")
+ "*Startup message for CVS.")
+
+(defvar cvs-cvs-buffer nil
+ "Internal to pcl-cvs.el.
+This variable exists in the *cvs-commit-message* buffer and names
+the *cvs* buffer.")
+
+;;; The cvs data structure:
+;;;
+;;; When the `cvs update' is ready we parse the output. Every file
+;;; that is affected in some way is added as a cookie of fileinfo
+;;; (as defined below).
+;;;
+
+;;; cvs-fileinfo
+;;;
+;;; marked t/nil
+;;; type One of
+;;; UPDATED - file copied from repository
+;;; MODIFIED - modified by you, unchanged in
+;;; repository
+;;; ADDED - added by you, not yet committed
+;;; REMOVED - removed by you, not yet committed
+;;; CVS-REMOVED- removed, since file no longer exists
+;;; in the repository.
+;;; MERGED - successful merge
+;;; CONFLICT - conflict when merging
+;;; REM-CONFLICT-removed in repository, changed locally.
+;;; MOD-CONFLICT-removed locally, changed in repository.
+;;; DIRCHANGE - A change of directory.
+;;; UNKNOWN - An unknown file.
+;;; MOVE-AWAY - A file that is in the way.
+;;; REPOS-MISSING- The directory is removed from the
+;;; repository. Go fetch a backup.
+;;; dir Directory the file resides in. Should not end with
+;;; slash.
+;;; file-name The file name.
+;;; backup-file Name of the backup file if MERGED or CONFLICT.
+;;; cvs-diff-buffer A buffer that contains a 'cvs diff file'.
+;;; backup-diff-buffer A buffer that contains a 'diff file backup-file'.
+;;; full-log The output from cvs, unparsed.
+;;; mod-time Modification time of file used for *-diff-buffer.
+;;; handled True if this file doesn't require further action.
+;;;
+;;; Constructor:
+
+;;; cvs-fileinfo
+
+;;; Constructor:
+
+(defun cvs-create-fileinfo (type
+ dir
+ file-name
+ full-log)
+ "Create a fileinfo from all parameters.
+Arguments: TYPE DIR FILE-NAME FULL-LOG.
+A fileinfo has the following fields:
+
+ marked t/nil
+ type One of
+ UPDATED - file copied from repository
+ MODIFIED - modified by you, unchanged in
+ repository
+ ADDED - added by you, not yet committed
+ REMOVED - removed by you, not yet committed
+ CVS-REMOVED- removed, since file no longer exists
+ in the repository.
+ MERGED - successful merge
+ CONFLICT - conflict when merging
+ REM-CONFLICT-removed in repository, but altered
+ locally.
+ MOD-CONFLICT-removed locally, changed in repository.
+ DIRCHANGE - A change of directory.
+ UNKNOWN - An unknown file.
+ MOVE-AWAY - A file that is in the way.
+ REPOS-MISSING- The directory has vanished from the
+ repository.
+ dir Directory the file resides in. Should not end with slash.
+ file-name The file name.
+ backup-file Name of the backup file if MERGED or CONFLICT.
+ cvs-diff-buffer A buffer that contains a 'cvs diff file'.
+ backup-diff-buffer A buffer that contains a 'diff file backup-file'.
+ full-log The output from cvs, unparsed.
+ mod-time Modification time of file used for *-diff-buffer.
+ handled True if this file doesn't require further action."
+ (cons
+ 'CVS-FILEINFO
+ (vector nil nil type dir file-name nil nil nil full-log nil)))
+
+
+;;; Selectors:
+
+(defun cvs-fileinfo->handled (cvs-fileinfo)
+ "Get the `handled' field from CVS-FILEINFO."
+ (elt (cdr cvs-fileinfo) 0))
+
+(defun cvs-fileinfo->marked (cvs-fileinfo)
+ "Check if CVS-FILEINFO is marked."
+ (elt (cdr cvs-fileinfo) 1))
+
+(defun cvs-fileinfo->type (cvs-fileinfo)
+ "Get type from CVS-FILEINFO.
+Type is one of UPDATED, MODIFIED, ADDED, REMOVED, CVS-REMOVED, MERGED,
+CONFLICT, REM-CONFLICT, MOD-CONFLICT, DIRCHANGE, UNKNOWN, MOVE-AWAY
+or REPOS-MISSING."
+ (elt (cdr cvs-fileinfo) 2))
+
+(defun cvs-fileinfo->dir (cvs-fileinfo)
+ "Get dir from CVS-FILEINFO.
+The directory name does not end with a slash. "
+ (elt (cdr cvs-fileinfo) 3))
+
+(defun cvs-fileinfo->file-name (cvs-fileinfo)
+ "Get file-name from CVS-FILEINFO."
+ (elt (cdr cvs-fileinfo) 4))
+
+(defun cvs-fileinfo->backup-file (cvs-fileinfo)
+ "Get backup-file from CVS-FILEINFO."
+ (elt (cdr cvs-fileinfo) 5))
+
+(defun cvs-fileinfo->cvs-diff-buffer (cvs-fileinfo)
+ "Get cvs-diff-buffer from CVS-FILEINFO."
+ (elt (cdr cvs-fileinfo) 6))
+
+(defun cvs-fileinfo->backup-diff-buffer (cvs-fileinfo)
+ "Get backup-diff-buffer from CVS-FILEINFO."
+ (elt (cdr cvs-fileinfo) 7))
+
+(defun cvs-fileinfo->full-log (cvs-fileinfo)
+ "Get full-log from CVS-FILEINFO."
+ (elt (cdr cvs-fileinfo) 8))
+
+(defun cvs-fileinfo->mod-time (cvs-fileinfo)
+ "Get mod-time from CVS-FILEINFO."
+ (elt (cdr cvs-fileinfo) 9))
+
+;;; Modifiers:
+
+(defun cvs-set-fileinfo->handled (cvs-fileinfo newval)
+ "Set handled in CVS-FILEINFO to NEWVAL."
+ (aset (cdr cvs-fileinfo) 0 newval))
+
+(defun cvs-set-fileinfo->marked (cvs-fileinfo newval)
+ "Set marked in CVS-FILEINFO to NEWVAL."
+ (aset (cdr cvs-fileinfo) 1 newval))
+
+(defun cvs-set-fileinfo->type (cvs-fileinfo newval)
+ "Set type in CVS-FILEINFO to NEWVAL."
+ (aset (cdr cvs-fileinfo) 2 newval))
+
+(defun cvs-set-fileinfo->dir (cvs-fileinfo newval)
+ "Set dir in CVS-FILEINFO to NEWVAL.
+The directory should now end with a slash."
+ (aset (cdr cvs-fileinfo) 3 newval))
+
+(defun cvs-set-fileinfo->file-name (cvs-fileinfo newval)
+ "Set file-name in CVS-FILEINFO to NEWVAL."
+ (aset (cdr cvs-fileinfo) 4 newval))
+
+(defun cvs-set-fileinfo->backup-file (cvs-fileinfo newval)
+ "Set backup-file in CVS-FILEINFO to NEWVAL."
+ (aset (cdr cvs-fileinfo) 5 newval))
+
+(defun cvs-set-fileinfo->cvs-diff-buffer (cvs-fileinfo newval)
+ "Set cvs-diff-buffer in CVS-FILEINFO to NEWVAL."
+ (aset (cdr cvs-fileinfo) 6 newval))
+
+(defun cvs-set-fileinfo->backup-diff-buffer (cvs-fileinfo newval)
+ "Set backup-diff-buffer in CVS-FILEINFO to NEWVAL."
+ (aset (cdr cvs-fileinfo) 7 newval))
+
+(defun cvs-set-fileinfo->full-log (cvs-fileinfo newval)
+ "Set full-log in CVS-FILEINFO to NEWVAL."
+ (aset (cdr cvs-fileinfo) 8 newval))
+
+(defun cvs-set-fileinfo->mod-time (cvs-fileinfo newval)
+ "Set full-log in CVS-FILEINFO to NEWVAL."
+ (aset (cdr cvs-fileinfo) 9 newval))
+
+
+
+;;; Predicate:
+
+(defun cvs-fileinfo-p (object)
+ "Return t if OBJECT is a cvs-fileinfo."
+ (eq (car-safe object) 'CVS-FILEINFO))
+
+;;;; End of types.
+
+(defun cvs-use-temp-buffer ()
+ "Display a temporary buffer in another window and select it.
+The selected window will not be changed. The temporary buffer will
+be erased and writable."
+
+ (display-buffer (get-buffer-create cvs-temp-buffer-name))
+ (set-buffer cvs-temp-buffer-name)
+ (setq buffer-read-only nil)
+ (erase-buffer))
+
+; Too complicated to handle all the cases that are generated.
+; Maybe later.
+;(defun cvs-examine (directory &optional local)
+; "Run a 'cvs -n update' in the current working directory.
+;That is, check what needs to be done, but don't change the disc.
+;Feed the output to a *cvs* buffer and run cvs-mode on it.
+;If optional prefix argument LOCAL is non-nil, 'cvs update -l' is run."
+; (interactive (list (read-file-name "CVS Update (directory): "
+; nil default-directory nil)
+; current-prefix-arg))
+; (cvs-do-update directory local 'noupdate))
+
+(defun cvs-update (directory &optional local)
+ "Run a 'cvs update' in the current working directory. Feed the
+output to a *cvs* buffer and run cvs-mode on it.
+If optional prefix argument LOCAL is non-nil, 'cvs update -l' is run."
+ (interactive (list (read-file-name "CVS Update (directory): "
+ nil default-directory nil)
+ current-prefix-arg))
+ (cvs-do-update directory local nil))
+
+(defun cvs-filter (predicate list &rest extra-args)
+ "Apply PREDICATE to each element on LIST.
+Args: PREDICATE LIST &rest EXTRA-ARGS.
+Return a new list consisting of those elements that PREDICATE
+returns non-nil for.
+
+If more than two arguments are given the remaining args are
+passed to PREDICATE."
+ ;; Avoid recursion - this should work for LONG lists also!
+ (let* ((head (cons 'dummy-header nil))
+ (tail head))
+ (while list
+ (if (apply predicate (car list) extra-args)
+ (setq tail (setcdr tail (list (car list)))))
+ (setq list (cdr list)))
+ (cdr head)))
+
+(defun cvs-update-no-prompt ()
+ "Run cvs update in current directory."
+ (interactive)
+ (cvs-do-update default-directory nil nil))
+
+(defun cvs-do-update (directory local dont-change-disc)
+ "Do a 'cvs update' in DIRECTORY.
+If LOCAL is non-nil 'cvs update -l' is executed.
+If DONT-CHANGE-DISC is non-nil 'cvs -n update' is executed.
+Both LOCAL and DONT-CHANGE-DISC may be non-nil simultaneously.
+
+*Note*: DONT-CHANGE-DISC does not yet work. The parser gets confused."
+ (save-some-buffers)
+ (let* ((this-dir (file-name-as-directory (expand-file-name directory)))
+ (use-this-window (equal (buffer-name (current-buffer))
+ cvs-buffer-name))
+ (update-buffer (generate-new-buffer
+ (concat (file-name-nondirectory
+ (substring this-dir 0 -1))
+ "-update")))
+ cvs-process args)
+
+ ;; The *cvs* buffer is killed to avoid confusion - is the update ready
+ ;; or not?
+ (if (get-buffer cvs-buffer-name)
+ (kill-buffer cvs-buffer-name))
+
+ ;; Generate "-n update -l".
+ (if local (setq args (list "-l")))
+ (setq args (cons "update" args))
+ (if dont-change-disc (setq args (cons "-n" args)))
+
+ ;; Set up the buffer that receives the output from "cvs update".
+ (if use-this-window
+ (switch-to-buffer update-buffer)
+ (set-buffer update-buffer)
+ (display-buffer update-buffer))
+
+ (setq default-directory this-dir)
+ (setq cvs-process
+ (let ((process-connection-type nil)) ; Use a pipe, not a pty.
+ (apply 'start-process "cvs" update-buffer cvs-program args)))
+
+ (setq mode-line-process
+ (concat ": "
+ (symbol-name (process-status cvs-process))))
+ (set-buffer-modified-p (buffer-modified-p)) ; Update the mode line.
+ (set-process-sentinel cvs-process 'cvs-sentinel)
+
+ ;; Work around a bug in emacs 18.57 and earlier.
+ (setq cvs-buffers-to-delete
+ (cvs-delete-unused-temporary-buffers cvs-buffers-to-delete))))
+
+(defun cvs-delete-unused-temporary-buffers (list)
+ "Delete all buffers on LIST that is not visible.
+Return a list of all buffers that still is alive."
+
+ (cond
+ ((null list) nil)
+ ((get-buffer-window (car list))
+ (cons (car list)
+ (cvs-delete-unused-temporary-buffers (cdr list))))
+ (t
+ (kill-buffer (car list))
+ (cvs-delete-unused-temporary-buffers (cdr list)))))
+
+
+(put 'cvs-mode 'mode-class 'special)
+
+(defun cvs-mode ()
+ "\\<cvs-mode-map>Mode used for pcl-cvs, a frontend to CVS.
+
+To get the *cvs* buffer you should use ``\\[cvs-update]''.
+
+Full documentation is in the TeXinfo file. These are the most useful commands:
+
+\\[cookie-previous-cookie] Move up. \\[cookie-next-cookie] Move down.
+\\[cvs-commit] Commit file. \\[cvs-update-no-prompt] Reupdate directory.
+\\[cvs-mark] Mark file/dir. \\[cvs-unmark] Unmark file/dir.
+\\[cvs-mark-all-files] Mark all files. \\[cvs-unmark-all-files] Unmark all files.
+\\[cvs-find-file] Edit file/run Dired. \\[cvs-find-file-other-window] Find file or run Dired in other window.
+\\[cvs-remove-handled] Remove processed entries. \\[cvs-add-change-log-entry-other-window] Write ChangeLog in other window.
+\\[cvs-add] Add to repository. \\[cvs-remove-file] Remove file.
+\\[cvs-diff-cvs] Diff between base revision. \\[cvs-diff-backup] Diff backup file.
+\\[cvs-acknowledge] Delete line from buffer. \\[cvs-ignore] Add file to the .cvsignore file.
+\\[cvs-log] Run ``cvs log''. \\[cvs-status] Run ``cvs status''.
+
+Entry to this mode runs cvs-mode-hook.
+This description is updated for release 1.02 of pcl-cvs.
+All bindings:
+\\{cvs-mode-map}"
+ (interactive)
+ (setq major-mode 'cvs-mode)
+ (setq mode-name "CVS")
+ (setq buffer-read-only nil)
+ (buffer-flush-undo (current-buffer))
+ (make-local-variable 'goal-column)
+ (setq goal-column cvs-cursor-column)
+ (use-local-map cvs-mode-map)
+ (run-hooks 'cvs-mode-hook))
+
+(defun cvs-sentinel (proc msg)
+ "Sentinel for the cvs update process.
+This is responsible for parsing the output from the cvs update when
+it is finished."
+ (cond
+ ((null (buffer-name (process-buffer proc)))
+ ;; buffer killed
+ (set-process-buffer proc nil))
+ ((memq (process-status proc) '(signal exit))
+ (let* ((obuf (current-buffer))
+ (omax (point-max))
+ (opoint (point)))
+ ;; save-excursion isn't the right thing if
+ ;; process-buffer is current-buffer
+ (unwind-protect
+ (progn
+ (set-buffer (process-buffer proc))
+ (setq mode-line-process
+ (concat ": "
+ (symbol-name (process-status proc))))
+ (cvs-parse-buffer)
+ (setq cvs-buffers-to-delete
+ (cons (process-buffer proc) cvs-buffers-to-delete)))
+ (set-buffer-modified-p (buffer-modified-p)))
+ (if (equal obuf (process-buffer proc))
+ nil
+ (set-buffer (process-buffer proc))
+ (if (< opoint omax)
+ (goto-char opoint))
+ (set-buffer obuf))))))
+
+(defun cvs-skip-line (regexp errormsg &optional arg)
+ "Like forward-line, but check that the skipped line matches REGEXP.
+If it doesn't match REGEXP (error ERRORMSG) is called.
+If optional ARG, a number, is given the ARGth parenthesized expression
+in the REGEXP is returned as a string.
+Point should be in column 1 when this function is called."
+ (cond
+ ((looking-at regexp)
+ (forward-line 1)
+ (if arg
+ (buffer-substring (match-beginning arg)
+ (match-end arg))))
+ (t
+ (error errormsg))))
+
+(defun cvs-get-current-dir (dirname)
+ "Return current working directory, suitable for cvs-parse-buffer.
+Args: DIRNAME.
+Concatenates default-directory and DIRNAME to form an absolute path."
+ (if (string= "." dirname)
+ (substring default-directory 0 -1)
+ (concat default-directory dirname)))
+
+
+(defun cvs-parse-buffer ()
+ "Parse the current buffer and select a *cvs* buffer.
+Signals an error if unexpected output was detected in the buffer."
+ (goto-char (point-min))
+ (let ((buf (get-buffer-create cvs-buffer-name))
+ (current-dir default-directory)
+ (root-dir default-directory)
+ (parse-buf (current-buffer)))
+
+ (cookie-create
+ buf 'cvs-pp cvs-startup-message ;Se comment above cvs-startup-message.
+ "---------- End -----")
+
+ (cookie-enter-first
+ buf
+ (cvs-create-fileinfo
+ 'DIRCHANGE current-dir
+ nil ""))
+
+ (while (< (point) (point-max))
+ (cond
+
+ ;; CVS is descending a subdirectory.
+
+ ((looking-at "cvs update: Updating \\(.*\\)$")
+ (setq current-dir
+ (cvs-get-current-dir
+ (buffer-substring (match-beginning 1) (match-end 1))))
+
+ ;; Omit empty directories.
+ (if (eq (cvs-fileinfo->type (cookie-last buf))
+ 'DIRCHANGE)
+ (cookie-delete-last buf))
+
+ (cookie-enter-last
+ buf
+ (cvs-create-fileinfo
+ 'DIRCHANGE current-dir
+ nil (buffer-substring (match-beginning 0)
+ (match-end 0))))
+ (forward-line 1))
+
+ ;; File removed, since it is removed (by third party) in repository.
+
+ ((or (looking-at "cvs update: warning: \\(.*\\) is not (any longer) \
+pertinent")
+ (looking-at "cvs update: \\(.*\\) is no longer in the repository"))
+ (cookie-enter-last
+ buf
+ (cvs-create-fileinfo
+ 'CVS-REMOVED current-dir
+ (file-name-nondirectory
+ (buffer-substring (match-beginning 1) (match-end 1)))
+ (buffer-substring (match-beginning 0)
+ (match-end 0))))
+ (forward-line 1))
+
+ ;; File removed by you, but recreated by cvs. Ignored.
+
+ ((looking-at "cvs update: warning: .* was lost$")
+ (forward-line 1))
+
+ ;; A file that has been created by you, but added to the cvs
+ ;; repository by another.
+
+ ((looking-at "^cvs update: move away \\(.*\\); it is in the way$")
+ (cookie-enter-last
+ buf
+ (cvs-create-fileinfo
+ 'MOVE-AWAY current-dir
+ (file-name-nondirectory
+ (buffer-substring (match-beginning 1) (match-end 1)))
+ (buffer-substring (match-beginning 0)
+ (match-end 0))))
+ (forward-line 1))
+
+ ;; Empty line. Probably inserted by mistake by user (or developer :-)
+ ;; Ignore.
+
+ ((looking-at "^$")
+ (forward-line 1))
+
+ ;; Cvs waits for a lock. Ignore.
+
+ ((looking-at
+ "^cvs update: \\[..:..:..\\] waiting for .*lock in ")
+ (forward-line 1))
+
+ ;; File removed in repository, but edited by you.
+
+ ((looking-at
+ "cvs update: conflict: \\(.*\\) is modified but no longer \
+in the repository$")
+ (cookie-enter-last
+ buf
+ (cvs-create-fileinfo
+ 'REM-CONFLICT current-dir
+ (file-name-nondirectory
+ (buffer-substring (match-beginning 1) (match-end 1)))
+ (buffer-substring (match-beginning 0)
+ (match-end 0))))
+ (forward-line 1))
+
+ ((looking-at
+ "cvs update: conflict: removed \\(.*\\) was modified by second party")
+ (cvs-create-fileinfo
+ 'MOD-CONFLICT current-dir
+ (buffer-substring (match-beginning 1) (match-end 1))
+ (buffer-substring (match-beginning 0) (match-end 0)))
+ (forward-line 1))
+
+ ((looking-at "cvs update: in directory ")
+ (let ((start (point)))
+ (forward-line 1)
+ (cvs-skip-line
+ (regexp-quote "cvs [update aborted]: there is no repository ")
+ "Unexpected cvs output.")
+ (cookie-enter-last
+ buf
+ (cvs-create-fileinfo
+ 'REPOS-MISSING current-dir
+ nil
+ (buffer-substring start (point))))))
+
+ ;; The file is copied from the repository.
+
+ ((looking-at "U \\(.*\\)$")
+ (cookie-enter-last
+ buf
+ (let ((fileinfo
+ (cvs-create-fileinfo
+ 'UPDATED current-dir
+ (file-name-nondirectory
+ (buffer-substring (match-beginning 1) (match-end 1)))
+ (buffer-substring (match-beginning 0) (match-end 0)))))
+ (cvs-set-fileinfo->handled fileinfo t)
+ fileinfo))
+ (forward-line 1))
+
+ ;; The file is modified by the user, and untouched in the repository.
+
+ ((looking-at "M \\(.*\\)$")
+ (cookie-enter-last
+ buf
+ (cvs-create-fileinfo
+ 'MODIFIED current-dir
+ (file-name-nondirectory
+ (buffer-substring (match-beginning 1) (match-end 1)))
+ (buffer-substring (match-beginning 0) (match-end 0))))
+ (forward-line 1))
+
+ ;; The file is "cvs add"ed, but not "cvs ci"ed.
+
+ ((looking-at "A \\(.*\\)$")
+ (cookie-enter-last
+ buf
+ (cvs-create-fileinfo
+ 'ADDED current-dir
+ (file-name-nondirectory
+ (buffer-substring (match-beginning 1) (match-end 1)))
+ (buffer-substring (match-beginning 0) (match-end 0))))
+ (forward-line 1))
+
+ ;; The file is "cvs remove"ed, but not "cvs ci"ed.
+
+ ((looking-at "R \\(.*\\)$")
+ (cookie-enter-last
+ buf
+ (cvs-create-fileinfo
+ 'REMOVED current-dir
+ (file-name-nondirectory
+ (buffer-substring (match-beginning 1) (match-end 1)))
+ (buffer-substring (match-beginning 0) (match-end 0))))
+ (forward-line 1))
+
+ ;; Unknown file.
+
+ ((looking-at "? \\(.*\\)$")
+ (cookie-enter-last
+ buf
+ (cvs-create-fileinfo
+ 'UNKNOWN current-dir
+ (file-name-nondirectory
+ (buffer-substring (match-beginning 1) (match-end 1)))
+ (buffer-substring (match-beginning 0) (match-end 0))))
+ (forward-line 1))
+ (t
+
+ ;; CVS has decided to merge someone elses changes into this
+ ;; document. This leads to a lot of garbage being printed.
+ ;; First there is two lines that contains no information
+ ;; that we skip (but we check that we recognize them).
+
+ (let ((complex-start (point))
+ initial-revision filename)
+
+ (cvs-skip-line "^RCS file: .*$" "Parse error.")
+ (setq initial-revision
+ (cvs-skip-line "^retrieving revision \\(.*\\)$"
+ "Unexpected output from cvs." 1))
+ (cvs-skip-line "^retrieving revision .*$"
+ "Unexpected output from cvs.")
+
+ ;; Get the file name from the next line.
+
+ (setq
+ filename
+ (cvs-skip-line
+ "^Merging differences between [0-9.]+ and [0-9.]+ into \\(.*\\)$"
+ "Unexpected output from cvs."
+ 1))
+
+ (cond
+
+ ;; The file was successfully merged.
+
+ ((looking-at "^M ")
+ (forward-line 1)
+ (let ((fileinfo
+ (cvs-create-fileinfo
+ 'MERGED current-dir
+ filename
+ (buffer-substring complex-start (point)))))
+ (cvs-set-fileinfo->backup-file
+ fileinfo
+ (concat cvs-bakprefix filename "." initial-revision))
+ (cookie-enter-last
+ buf fileinfo)))
+
+ ;; A conflicting merge.
+
+ (t
+ (cvs-skip-line "^merge: overlaps during merge$"
+ "Unexpected output from cvs.")
+ (cvs-skip-line "^cvs update: conflicts found in "
+ "Unexpected output from cvs.")
+ (cvs-skip-line "^C " "Unexpected cvs output.")
+ (let ((fileinfo
+ (cvs-create-fileinfo
+ 'CONFLICT current-dir
+ filename
+ (buffer-substring complex-start (point)))))
+
+ (cvs-set-fileinfo->backup-file
+ fileinfo
+ (concat cvs-bakprefix filename "." initial-revision))
+
+ (cookie-enter-last buf fileinfo))))))))
+
+ ;; All parsing is done.
+
+ ;; If the last entry is a directory, remove it.
+ (if (eq (cvs-fileinfo->type (cookie-last buf))
+ 'DIRCHANGE)
+ (cookie-delete-last buf))
+
+ (set-buffer buf)
+ (cvs-mode)
+ (setq cookie-last-tin (cookie-nth buf 0))
+ (goto-char (point-min))
+ (cookie-previous-cookie buf (point-min) 1)
+ (setq default-directory root-dir)
+ (if (get-buffer-window parse-buf)
+ (set-window-buffer (get-buffer-window parse-buf) buf)
+ (display-buffer buf))))
+
+
+(defun cvs-pp (fileinfo)
+ "Pretty print FILEINFO into a string."
+
+ (let ((a (cvs-fileinfo->type fileinfo))
+ (s (if (cvs-fileinfo->marked fileinfo)
+ "*" " "))
+ (f (cvs-fileinfo->file-name fileinfo))
+ (ci (if (cvs-fileinfo->handled fileinfo)
+ " " "ci")))
+ (cond
+ ((eq a 'UPDATED)
+ (format "%s Updated %s" s f))
+ ((eq a 'MODIFIED)
+ (format "%s Modified %s %s" s ci f))
+ ((eq a 'MERGED)
+ (format "%s Merged %s %s" s ci f))
+ ((eq a 'CONFLICT)
+ (format "%s Conflict %s" s f))
+ ((eq a 'ADDED)
+ (format "%s Added %s %s" s ci f))
+ ((eq a 'REMOVED)
+ (format "%s Removed %s %s" s ci f))
+ ((eq a 'UNKNOWN)
+ (format "%s Unknown %s" s f))
+ ((eq a 'CVS-REMOVED)
+ (format "%s Removed from repository: %s" s f))
+ ((eq a 'REM-CONFLICT)
+ (format "%s Conflict: Removed from repository, changed by you: %s" s f))
+ ((eq a 'MOD-CONFLICT)
+ (format "%s Conflict: Removed by you, changed in repository: %s" s f))
+ ((eq a 'DIRCHANGE)
+ (format "\nIn directory %s:"
+ (cvs-fileinfo->dir fileinfo)))
+ ((eq a 'MOVE-AWAY)
+ (format "%s Move away %s - it is in the way" s f))
+ ((eq a 'REPOS-MISSING)
+ (format " This repository is missing! Remove this dir manually."))
+ (t
+ (format "%s Internal error! %s" s f)))))
+
+
+;;; You can define your own keymap in .emacs. pcl-cvs.el won't overwrite it.
+
+(if cvs-mode-map
+ nil
+ (setq cvs-mode-map (make-keymap))
+ (suppress-keymap cvs-mode-map)
+ (define-key cvs-mode-map " " 'cookie-next-cookie)
+ (define-key cvs-mode-map "?" 'describe-mode)
+ (define-key cvs-mode-map "A" 'cvs-add-change-log-entry-other-window)
+ (define-key cvs-mode-map "M" 'cvs-mark-all-files)
+ (define-key cvs-mode-map "U" 'cvs-unmark-all-files)
+ (define-key cvs-mode-map "\C-?" 'cvs-unmark-up)
+ (define-key cvs-mode-map "\C-n" 'cookie-next-cookie)
+ (define-key cvs-mode-map "\C-p" 'cookie-previous-cookie)
+ (define-key cvs-mode-map "a" 'cvs-add)
+ (define-key cvs-mode-map "b" 'cvs-diff-backup)
+ (define-key cvs-mode-map "c" 'cvs-commit)
+ (define-key cvs-mode-map "d" 'cvs-diff-cvs)
+ (define-key cvs-mode-map "f" 'cvs-find-file)
+ (define-key cvs-mode-map "g" 'cvs-update-no-prompt)
+ (define-key cvs-mode-map "i" 'cvs-ignore)
+ (define-key cvs-mode-map "l" 'cvs-log)
+ (define-key cvs-mode-map "m" 'cvs-mark)
+ (define-key cvs-mode-map "n" 'cookie-next-cookie)
+ (define-key cvs-mode-map "o" 'cvs-find-file-other-window)
+ (define-key cvs-mode-map "p" 'cookie-previous-cookie)
+ (define-key cvs-mode-map "r" 'cvs-remove-file)
+ (define-key cvs-mode-map "s" 'cvs-status)
+ (define-key cvs-mode-map "\C-k" 'cvs-acknowledge)
+ (define-key cvs-mode-map "x" 'cvs-remove-handled)
+ (define-key cvs-mode-map "u" 'cvs-unmark))
+
+
+(defun cvs-get-marked ()
+ "Return a list of all selected tins.
+If there are any marked tins, return them.
+Otherwise, if the cursor selects a directory, return all files in it.
+Otherwise return (a list containing) the file the cursor points to, or
+an empty list if it doesn't point to a file at all."
+
+ (cond
+ ;; Any marked cookies?
+ ((cookie-collect-tins (current-buffer)
+ 'cvs-fileinfo->marked))
+ ;; Nope.
+ (t
+ (let ((sel (cookie-get-selection
+ (current-buffer) (point) cookie-last-tin)))
+ (cond
+ ;; If a directory is selected, all it members are returned.
+ ((and sel (eq (cvs-fileinfo->type
+ (cookie-cookie (current-buffer) sel))
+ 'DIRCHANGE))
+ (cookie-collect-tins
+ (current-buffer) 'cvs-dir-member-p
+ (cvs-fileinfo->dir (cookie-cookie (current-buffer) sel))))
+ (t
+ (list sel)))))))
+
+
+(defun cvs-dir-member-p (fileinfo dir)
+ "Return true if FILEINFO represents a file in directory DIR."
+ (and (not (eq (cvs-fileinfo->type fileinfo) 'DIRCHANGE))
+ (string= (cvs-fileinfo->dir fileinfo) dir)))
+
+(defun cvs-dir-empty-p (cvs-buf tin)
+ "Return non-nil if TIN is a directory that is empty.
+Args: CVS-BUF TIN."
+ (and (eq (cvs-fileinfo->type (cookie-cookie cvs-buf tin)) 'DIRCHANGE)
+ (or (not (cookie-next cvs-buf tin))
+ (eq (cvs-fileinfo->type (cookie-cookie cvs-buf
+ (cookie-next cvs-buf tin)))
+ 'DIRCHANGE))))
+
+(defun cvs-remove-handled ()
+ "Remove all lines that are handled.
+Empty directories are removed."
+ (interactive)
+ ;; Pass one: remove files that are handled.
+ (cookie-filter (current-buffer)
+ (function
+ (lambda (fileinfo) (not (cvs-fileinfo->handled fileinfo)))))
+ ;; Pass two: remove empty directories.
+ (cookie-filter-tins (current-buffer)
+ (function
+ (lambda (tin)
+ (not (cvs-dir-empty-p (current-buffer) tin))))))
+
+(defun cvs-mark (pos)
+ "Mark a fileinfo. Args: POS.
+If the fileinfo is a directory, all the contents of that directory are
+marked instead. A directory can never be marked.
+POS is a buffer position."
+
+ (interactive "d")
+
+ (let* ((tin (cookie-get-selection
+ (current-buffer) pos cookie-last-tin))
+ (sel (cookie-cookie (current-buffer) tin)))
+
+ (cond
+ ;; Does POS point to a directory? If so, mark all files in that directory.
+ ((eq (cvs-fileinfo->type sel) 'DIRCHANGE)
+ (cookie-map
+ (function (lambda (f dir)
+ (cond
+ ((cvs-dir-member-p f dir)
+ (cvs-set-fileinfo->marked f t)
+ t)))) ;Tell cookie to redisplay this cookie.
+ (current-buffer)
+ (cvs-fileinfo->dir sel)))
+ (t
+ (cvs-set-fileinfo->marked sel t)
+ (cookie-invalidate-tins (current-buffer) tin)
+ (cookie-next-cookie (current-buffer) pos 1)))))
+
+
+(defun cvs-committable (tin cvs-buf)
+ "Check if the TIN is committable.
+It is committable if it
+ a) is not handled and
+ b) is either MODIFIED, ADDED, REMOVED, MERGED or CONFLICT."
+ (let* ((fileinfo (cookie-cookie cvs-buf tin))
+ (type (cvs-fileinfo->type fileinfo)))
+ (and (not (cvs-fileinfo->handled fileinfo))
+ (or (eq type 'MODIFIED)
+ (eq type 'ADDED)
+ (eq type 'REMOVED)
+ (eq type 'MERGED)
+ (eq type 'CONFLICT)))))
+
+(defun cvs-commit ()
+
+ "Check in all marked files, or the current file.
+The user will be asked for a log message in a buffer.
+If cvs-erase-input-buffer is non-nil that buffer will be erased.
+Otherwise mark and point will be set around the entire contents of the
+buffer so that it is easy to kill the contents of the buffer with \\[kill-region]."
+
+ (interactive)
+
+ (let* ((cvs-buf (current-buffer))
+ (marked (cvs-filter (function cvs-committable)
+ (cvs-get-marked)
+ cvs-buf)))
+ (if (null marked)
+ (error "Nothing to commit!")
+ (pop-to-buffer (get-buffer-create cvs-commit-prompt-buffer))
+ (goto-char (point-min))
+
+ (if cvs-erase-input-buffer
+ (erase-buffer)
+ (push-mark (point-max)))
+ (cvs-edit-mode)
+ (make-local-variable 'cvs-commit-list)
+ (setq cvs-commit-list marked)
+ (make-local-variable 'cvs-cvs-buffer)
+ (setq cvs-cvs-buffer cvs-buf)
+ (message "Press C-c C-c when you are done editing."))))
+
+
+(defun cvs-edit-done ()
+ "Commit the files to the repository."
+ (interactive)
+ (save-some-buffers)
+ (let ((cc-list cvs-commit-list)
+ (cc-buffer cvs-cvs-buffer)
+ (msg-buffer (current-buffer))
+ (msg (buffer-substring (point-min) (point-max))))
+ (pop-to-buffer cc-buffer)
+ (bury-buffer msg-buffer)
+ (cvs-use-temp-buffer)
+ (message "Committing...")
+ (cvs-execute-list cc-list cvs-program (list "commit" "-m" msg))
+ (mapcar (function
+ (lambda (tin)
+ (cvs-set-fileinfo->handled (cookie-cookie cc-buffer tin) t)))
+ cc-list)
+ (apply 'cookie-invalidate-tins cc-buffer cc-list)
+ (set-buffer cc-buffer)
+ (if cvs-auto-remove-handled
+ (cvs-remove-handled)))
+
+ (message "Committing... Done."))
+
+
+(defun cvs-execute-list (tin-list program constant-args)
+ "Run PROGRAM on all elements on TIN-LIST.
+Args: TIN-LIST PROGRAM CONSTANT-ARGS
+The PROGRAM will be called with pwd set to the directory the
+files reside in. CONSTANT-ARGS should be a list of strings. The
+arguments given to the program will be CONSTANT-ARGS followed by all
+the files (from TIN-LIST) that resides in that directory. If the files
+in TIN-LIST resides in different directories the PROGRAM will be run
+once for each directory (if all files in the same directory appears
+after each other."
+
+ (while tin-list
+ (let ((current-dir (cvs-fileinfo->dir
+ (cookie-cookie cvs-buffer-name
+ (car tin-list))))
+ arg-list arg-str)
+
+ ;; Collect all marked files in this directory.
+
+ (while (and tin-list
+ (string=
+ current-dir
+ (cvs-fileinfo->dir
+ (cookie-cookie cvs-buffer-name (car tin-list)))))
+ (setq arg-list
+ (cons (cvs-fileinfo->file-name
+ (cookie-cookie cvs-buffer-name (car tin-list)))
+ arg-list))
+ (setq tin-list (cdr tin-list)))
+
+ (setq arg-list (nreverse arg-list))
+
+ ;; Execute the command on all the files that were collected.
+
+ (setq default-directory (file-name-as-directory current-dir))
+ (insert (format "=== cd %s\n" default-directory))
+ (insert (format "=== %s %s\n\n"
+ program
+ (mapconcat '(lambda (foo) foo)
+ (nconc (copy-sequence constant-args)
+ arg-list)
+ " ")))
+ (apply 'call-process program nil t t
+ (nconc (copy-sequence constant-args) arg-list))
+ (goto-char (point-max)))))
+
+
+(defun cvs-execute-single-file-list (tin-list extractor program constant-args)
+ "Run PROGRAM on all elements on TIN-LIST.
+
+Args: TIN-LIST EXTRACTOR PROGRAM CONSTANT-ARGS
+
+The PROGRAM will be called with pwd set to the directory the files
+reside in. CONSTANT-ARGS is a list of strings to pass as arguments to
+PROGRAM. The arguments given to the program will be CONSTANT-ARGS
+followed by the list that EXTRACTOR returns.
+
+EXTRACTOR will be called once for each file on TIN-LIST. It is given
+one argument, the cvs-fileinfo. It can return t, which means ignore
+this file, or a list of arguments to send to the program."
+
+ (while tin-list
+ (let ((default-directory (file-name-as-directory
+ (cvs-fileinfo->dir
+ (cookie-cookie cvs-buffer-name
+ (car tin-list)))))
+ (arg-list
+ (funcall extractor
+ (cookie-cookie cvs-buffer-name (car tin-list)))))
+
+ ;; Execute the command unless extractor returned t.
+
+ (if (eq arg-list t)
+ nil
+ (insert (format "=== cd %s\n" default-directory))
+ (insert (format "=== %s %s\n\n"
+ program
+ (mapconcat '(lambda (foo) foo)
+ (nconc (copy-sequence constant-args)
+ arg-list)
+ " ")))
+ (apply 'call-process program nil t t
+ (nconc (copy-sequence constant-args) arg-list))
+ (goto-char (point-max))))
+ (setq tin-list (cdr tin-list))))
+
+
+(defun cvs-edit-mode ()
+ "\\<cvs-edit-mode-map>Mode for editing cvs log messages.
+Commands:
+\\[cvs-edit-done] checks in the file when you are ready.
+This mode is based on fundamental mode."
+ (interactive)
+ (use-local-map cvs-edit-mode-map)
+ (setq major-mode 'cvs-edit-mode)
+ (setq mode-name "CVS Log")
+ (auto-fill-mode 1))
+
+
+(if cvs-edit-mode-map
+ nil
+ (setq cvs-edit-mode-map (make-sparse-keymap))
+ (define-prefix-command 'cvs-control-c-prefix)
+ (define-key cvs-edit-mode-map "\C-c" 'cvs-control-c-prefix)
+ (define-key cvs-edit-mode-map "\C-c\C-c" 'cvs-edit-done))
+
+
+(defun cvs-diff-cvs ()
+ "Diff the selected files against the repository.
+The flags the variable cvs-cvs-diff-flags will be passed to ``cvs diff''."
+ (interactive)
+
+ (save-some-buffers)
+ (let ((marked (cvs-get-marked)))
+ (cvs-use-temp-buffer)
+ (message "cvsdiffing...")
+ (cvs-execute-list marked cvs-program (cons "diff" cvs-cvs-diff-flags)))
+ (message "cvsdiffing... Done."))
+
+
+(defun cvs-backup-diffable (tin cvs-buf)
+ "Check if the TIN is backup-diffable.
+It must have a backup file to be diffable."
+ (cvs-fileinfo->backup-file (cookie-cookie cvs-buf tin)))
+
+(defun cvs-diff-backup ()
+ "Diff the files against the backup file.
+This command can be used on files that are marked with \"Merged\"
+or \"Conflict\" in the *cvs* buffer.
+
+The flags in cvs-diff-flags will be passed to ``diff''."
+
+ (interactive)
+ (save-some-buffers)
+ (let ((marked (cvs-filter (function cvs-backup-diffable)
+ (cvs-get-marked)
+ (current-buffer))))
+ (if (null marked)
+ (error "No ``Conflict'' or ``Merged'' file selected!"))
+ (cvs-use-temp-buffer)
+ (message "diffing...")
+ (cvs-execute-single-file-list
+ marked 'cvs-diff-backup-extractor cvs-diff-program cvs-diff-flags))
+ (message "diffing... Done."))
+
+
+(defun cvs-diff-backup-extractor (fileinfo)
+ "Return the filename and the name of the backup file as a list.
+Signal an error if there is no backup file."
+ (if (null (cvs-fileinfo->backup-file fileinfo))
+ (error "%s has no backup file."
+ (concat
+ (file-name-as-directory (cvs-fileinfo->dir fileinfo))
+ (cvs-fileinfo->file-name fileinfo))))
+ (list (cvs-fileinfo->file-name fileinfo)
+ (cvs-fileinfo->backup-file fileinfo)))
+
+(defun cvs-find-file-other-window (pos)
+ "Select a buffer containing the file in another window.
+Args: POS"
+ (interactive "d")
+ (save-some-buffers)
+ (let* ((cookie-last-tin
+ (cookie-get-selection (current-buffer) pos cookie-last-tin))
+ (type (cvs-fileinfo->type (cookie-cookie (current-buffer)
+ cookie-last-tin))))
+ (cond
+ ((or (eq type 'REMOVED)
+ (eq type 'CVS-REMOVED))
+ (error "Can't visit a removed file."))
+ ((eq type 'DIRCHANGE)
+ (let ((obuf (current-buffer))
+ (odir default-directory))
+ (setq default-directory
+ (file-name-as-directory
+ (cvs-fileinfo->dir
+ (cookie-cookie (current-buffer) cookie-last-tin))))
+ (dired-other-window default-directory)
+ (set-buffer obuf)
+ (setq default-directory odir)))
+ (t
+ (find-file-other-window (cvs-full-path (current-buffer)
+ cookie-last-tin))))))
+
+(defun cvs-full-path (buffer tin)
+ "Return the full path for the file that is described in TIN.
+Args: BUFFER TIN."
+ (concat
+ (file-name-as-directory
+ (cvs-fileinfo->dir (cookie-cookie buffer tin)))
+ (cvs-fileinfo->file-name (cookie-cookie buffer tin))))
+
+(defun cvs-find-file (pos)
+ "Select a buffer containing the file in another window.
+Args: POS"
+ (interactive "d")
+ (let* ((cvs-buf (current-buffer))
+ (cookie-last-tin (cookie-get-selection cvs-buf pos cookie-last-tin))
+ (fileinfo (cookie-cookie cvs-buf cookie-last-tin))
+ (type (cvs-fileinfo->type fileinfo)))
+ (cond
+ ((or (eq type 'REMOVED)
+ (eq type 'CVS-REMOVED))
+ (error "Can't visit a removed file."))
+ ((eq type 'DIRCHANGE)
+ (let ((odir default-directory))
+ (setq default-directory
+ (file-name-as-directory (cvs-fileinfo->dir fileinfo)))
+ (dired default-directory)
+ (set-buffer cvs-buf)
+ (setq default-directory odir)))
+ (t
+ (find-file (cvs-full-path cvs-buf cookie-last-tin))))))
+
+(defun cvs-mark-all-files ()
+ "Mark all files.
+Directories are not marked."
+ (interactive)
+ (cookie-map (function (lambda (cookie)
+ (cond
+ ((not (eq (cvs-fileinfo->type cookie) 'DIRCHANGE))
+ (cvs-set-fileinfo->marked cookie t)
+ t))))
+ (current-buffer)))
+
+
+(defun cvs-unmark (pos)
+ "Unmark a fileinfo. Args: POS."
+ (interactive "d")
+
+ (let* ((tin (cookie-get-selection
+ (current-buffer) pos cookie-last-tin))
+ (sel (cookie-cookie (current-buffer) tin)))
+
+ (cond
+ ((eq (cvs-fileinfo->type sel) 'DIRCHANGE)
+ (cookie-map
+ (function (lambda (f dir)
+ (cond
+ ((cvs-dir-member-p f dir)
+ (cvs-set-fileinfo->marked f nil)
+ t))))
+ (current-buffer)
+ (cvs-fileinfo->dir sel)))
+ (t
+ (cvs-set-fileinfo->marked sel nil)
+ (cookie-invalidate-tins (current-buffer) tin)
+ (cookie-next-cookie (current-buffer) pos 1)))))
+
+(defun cvs-unmark-all-files ()
+ "Unmark all files.
+Directories are also unmarked, but that doesn't matter, since
+they should always be unmarked."
+ (interactive)
+ (cookie-map (function (lambda (cookie)
+ (cvs-set-fileinfo->marked cookie nil)
+ t))
+ (current-buffer)))
+
+
+(defun cvs-do-removal (cvs-buf tins)
+ "Remove files.
+Args: CVS-BUF TINS.
+CVS-BUF is the cvs buffer. TINS is a list of tins that the
+user wants to delete. The files are deleted. If the type of
+the tin is 'UNKNOWN the tin is removed from the buffer. If it
+is anything else the file is added to a list that should be
+`cvs remove'd and the tin is changed to be of type 'REMOVED.
+
+Returns a list of tins files that should be `cvs remove'd."
+ (cvs-use-temp-buffer)
+ (mapcar 'cvs-insert-full-path tins)
+ (cond
+ ((and tins (yes-or-no-p (format "Delete %d files? " (length tins))))
+ (let (files-to-remove)
+ (while tins
+ (let* ((tin (car tins))
+ (fileinfo (cookie-cookie cvs-buf tin))
+ (type (cvs-fileinfo->type fileinfo)))
+ (if (not (or (eq type 'REMOVED) (eq type 'CVS-REMOVED)))
+ (progn
+ (delete-file (cvs-full-path cvs-buf tin))
+ (cond
+ ((or (eq type 'UNKNOWN) (eq type 'MOVE-AWAY))
+ (cookie-delete cvs-buf tin))
+ (t
+ (setq files-to-remove (cons tin files-to-remove))
+ (cvs-set-fileinfo->type fileinfo 'REMOVED)
+ (cvs-set-fileinfo->handled fileinfo nil)
+ (cookie-invalidate-tins cvs-buf tin))))))
+ (setq tins (cdr tins)))
+ files-to-remove))
+ (t nil)))
+
+
+
+(defun cvs-remove-file ()
+ "Remove all marked files."
+ (interactive)
+ (let ((files-to-remove (cvs-do-removal (current-buffer) (cvs-get-marked))))
+ (if (null files-to-remove)
+ nil
+ (cvs-use-temp-buffer)
+ (message "removing from repository...")
+ (cvs-execute-list files-to-remove cvs-program '("remove"))
+ (message "removing from repository... done."))))
+
+(defun cvs-acknowledge ()
+ "Remove all marked files from the buffer."
+ (interactive)
+
+ (mapcar (function (lambda (tin)
+ (cookie-delete (current-buffer) tin)))
+ (cvs-get-marked))
+ (setq cookie-last-tin nil))
+
+
+(defun cvs-unmark-up (pos)
+ "Unmark the file on the previous line.
+Takes one argument POS, a buffer position."
+ (interactive "d")
+ (cookie-previous-cookie (current-buffer) pos 1)
+ (cvs-set-fileinfo->marked (cookie-cookie (current-buffer) cookie-last-tin)
+ nil)
+ (cookie-invalidate-tins (current-buffer) cookie-last-tin))
+
+(defun cvs-add-file-update-buffer (cvs-buf tin)
+ "Subfunction to cvs-add. Internal use only.
+Update the display. Return non-nil if `cvs add' should be called on this
+file. Args: CVS-BUF TIN.
+Returns 'ADD or 'RESURRECT."
+ (let ((fileinfo (cookie-cookie cvs-buf tin)))
+ (cond
+ ((eq (cvs-fileinfo->type fileinfo) 'UNKNOWN)
+ (cvs-set-fileinfo->type fileinfo 'ADDED)
+ (cookie-invalidate-tins cvs-buf tin)
+ 'ADD)
+ ((eq (cvs-fileinfo->type fileinfo) 'REMOVED)
+ (cvs-set-fileinfo->type fileinfo 'UPDATED)
+ (cvs-set-fileinfo->handled fileinfo t)
+ (cookie-invalidate-tins cvs-buf tin)
+ 'RESURRECT))))
+
+(defun cvs-add-sub (cvs-buf candidates)
+ "Internal use only.
+Args: CVS-BUF CANDIDATES.
+CANDIDATES is a list of tins. Updates the CVS-BUF and returns a pair of lists.
+The first list is unknown tins that shall be `cvs add -m msg'ed.
+The second list is removed files that shall be `cvs add'ed (resurrected)."
+ (let (add resurrect)
+ (while candidates
+ (let ((type (cvs-add-file-update-buffer cvs-buf (car candidates))))
+ (cond ((eq type 'ADD)
+ (setq add (cons (car candidates) add)))
+ ((eq type 'RESURRECT)
+ (setq resurrect (cons (car candidates) resurrect)))))
+ (setq candidates (cdr candidates)))
+ (cons add resurrect)))
+
+(defun cvs-add ()
+ "Add marked files to the cvs repository."
+ (interactive)
+
+ (let* ((buf (current-buffer))
+ (result (cvs-add-sub buf (cvs-get-marked)))
+ (added (car result))
+ (resurrect (cdr result))
+ (msg (if added (read-from-minibuffer "Enter description: "))))
+
+ (if (or resurrect added)
+ (cvs-use-temp-buffer))
+
+ (cond (resurrect
+ (message "Resurrecting files from repository...")
+ (cvs-execute-list resurrect cvs-program '("add"))
+ (message "Done.")))
+
+ (cond (added
+ (message "Adding new files to repository...")
+ (cvs-execute-list added cvs-program (list "add" "-m" msg))
+ (message "Done.")))))
+
+(defun cvs-ignore ()
+ "Arrange so that CVS ignores the selected files.
+This command ignores files that are not flagged as `Unknown'."
+ (interactive)
+
+ (mapcar (function (lambda (tin)
+ (cond
+ ((eq (cvs-fileinfo->type
+ (cookie-cookie (current-buffer) tin)) 'UNKNOWN)
+ (cvs-append-to-ignore
+ (cookie-cookie (current-buffer) tin))
+ (cookie-delete (current-buffer) tin)))))
+ (cvs-get-marked))
+ (setq cookie-last-tin nil))
+
+(defun cvs-append-to-ignore (fileinfo)
+ "Append the file in fileinfo to the .cvsignore file"
+ (save-window-excursion
+ (set-buffer (find-file-noselect (concat (file-name-as-directory
+ (cvs-fileinfo->dir fileinfo))
+ ".cvsignore")))
+ (goto-char (point-max))
+ (if (not (zerop (current-column)))
+ (insert "\n"))
+ (insert (cvs-fileinfo->file-name fileinfo) "\n")
+ (save-buffer)))
+
+(defun cvs-status ()
+ "Show cvs status for all marked files."
+ (interactive)
+
+ (save-some-buffers)
+ (let ((marked (cvs-get-marked)))
+ (cvs-use-temp-buffer)
+ (message "Running cvs status ...")
+ (cvs-execute-list marked cvs-program (cons "status" cvs-status-flags)))
+ (message "Running cvs status ... Done."))
+
+(defun cvs-log ()
+ "Display the cvs log of all selected files."
+ (interactive)
+
+ (let ((marked (cvs-get-marked)))
+ (cvs-use-temp-buffer)
+ (message "Running cvs log ...")
+ (cvs-execute-list marked cvs-program (cons "log" cvs-log-flags)))
+ (message "Running cvs log ... Done."))
+
+
+(defun cvs-insert-full-path (tin)
+ "Insert full path to the file described in TIN."
+ (insert (format "%s\n" (cvs-full-path cvs-buffer-name tin))))
+
+
+(defun cvs-add-change-log-entry-other-window (pos)
+ "Add a ChangeLog entry in the ChangeLog of the current directory.
+Args: POS."
+ (interactive "d")
+ (let* ((cvs-buf (current-buffer))
+ (odir default-directory))
+ (setq default-directory
+ (file-name-as-directory
+ (cvs-fileinfo->dir
+ (cookie-cookie
+ cvs-buf
+ (cookie-get-selection cvs-buf pos cookie-last-tin)))))
+ (if (not default-directory) ;In case there was no entries.
+ (setq default-directory odir))
+ (add-change-log-entry-other-window)
+ (set-buffer cvs-buf)
+ (setq default-directory odir)))
+
+
+(defun print-cvs-tin (foo)
+ "Debug utility."
+ (let ((cookie (cookie-cookie (current-buffer) foo))
+ (stream (get-buffer-create "debug")))
+ (princ "==============\n" stream)
+ (princ (cvs-fileinfo->file-name cookie) stream)
+ (princ "\n" stream)
+ (princ (cvs-fileinfo->dir cookie) stream)
+ (princ "\n" stream)
+ (princ (cvs-fileinfo->full-log cookie) stream)
+ (princ "\n" stream)
+ (princ (cvs-fileinfo->marked cookie) stream)
+ (princ "\n" stream)))
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.info b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.info
new file mode 100644
index 000000000000..3c0d3c08e590
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.info
@@ -0,0 +1,1367 @@
+Info file pcl-cvs, produced by Makeinfo, -*- Text -*- from input
+file pcl-cvs.texinfo.
+
+ Copyright (C) 1992 Per Cederqvist
+
+ Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+ Permission is granted to copy and distribute modified versions of
+this manual under the conditions for verbatim copying, provided also
+that the section entitled "GNU General Public License" is included
+exactly as in the original, and provided that the entire resulting
+derived work is distributed under the terms of a permission notice
+identical to this one.
+
+ Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for
+modified versions, except that the section entitled "GNU General
+Public License" and this permission notice may be included in
+translations approved by the Free Software Foundation instead of in
+the original English.
+
+
+File: pcl-cvs, Node: Top, Next: Copying, Prev: (dir), Up: (dir)
+
+ This info manual describes pcl-cvs which is a GNU Emacs front-end
+to CVS. It works with CVS version 1.3. This manual is updated to
+release 1.02 of pcl-cvs.
+
+* Menu:
+
+* Copying:: GNU General Public License
+* Installation:: How to install pcl-cvs on your system.
+* About pcl-cvs:: Authors and ftp sites.
+
+* Getting started:: An introduction with a walk-through example.
+* Buffer contents:: An explanation of the buffer contents.
+* Commands:: All commands, grouped by type.
+
+* Customization:: How you can tailor pcl-cvs to suit your needs.
+* Future enhancements:: Future enhancements of pcl-cvs.
+* Reporting bugs and ideas:: Where to report bugs.
+
+* Function and Variable Index:: List of functions and variables.
+* Concept Index:: List of concepts.
+* Key Index:: List of keystrokes.
+
+ -- The Detailed Node Listing --
+
+Installation
+
+* Pcl-cvs installation:: How to install pcl-cvs on your system.
+* On-line manual installation:: How to install the on-line manual.
+* Typeset manual installation:: How to create typeset documentation
+ about pcl-cvs.
+
+About pcl-cvs
+
+* Contributors:: Contributors to pcl-cvs.
+* Archives:: Where can I get a copy of Pcl-Cvs?
+
+Buffer contents
+
+* File status:: The meaning of the second field.
+* Selected files:: How selection works.
+
+Commands
+
+* Updating the directory:: Commands to update the local directory
+* Movement commands:: How to move up and down in the buffer
+* Marking files:: How to mark files that other commands
+ will later operate on.
+* Committing changes:: Checking in your modifications to the
+ CVS repository.
+* Editing files:: Loading files into Emacs.
+* Getting info about files:: Display the log and status of files.
+* Adding and removing files:: Adding and removing files
+* Removing handled entries:: Uninteresting lines can easily be removed.
+* Ignoring files:: Telling CVS to ignore generated files.
+* Viewing differences:: Commands to `diff' different versions.
+
+
+File: pcl-cvs, Node: Copying, Next: Installation, Prev: Top, Up: Top
+
+GNU GENERAL PUBLIC LICENSE
+**************************
+
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+Preamble
+========
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+This General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit
+to using it. (Some other Free Software Foundation software is
+covered by the GNU Library General Public License instead.) You can
+apply it to your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and
+charge for this service if you wish), that you receive source code
+or can get it if you want it, that you can change the software or
+use pieces of it in new free programs; and that you know you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the
+rights. These restrictions translate to certain responsibilities
+for you if you distribute copies of the software, or if you modify
+it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the
+software, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make
+certain that everyone understands that there is no warranty for this
+free software. If the software is modified by someone else and
+passed on, we want its recipients to know that what they have is not
+the original, so that any problems introduced by others will not
+reflect on the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making
+the program proprietary. To prevent this, we have made it clear
+that any patent must be licensed for everyone's free use or not
+licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 1. This License applies to any program or other work which contains
+ a notice placed by the copyright holder saying it may be
+ distributed under the terms of this General Public License.
+ The "Program", below, refers to any such program or work, and a
+ "work based on the Program" means either the Program or any
+ derivative work under copyright law: that is to say, a work
+ containing the Program or a portion of it, either verbatim or
+ with modifications and/or translated into another language.
+ (Hereinafter, translation is included without limitation in the
+ term "modification".) Each licensee is addressed as "you".
+
+ Activities other than copying, distribution and modification
+ are not covered by this License; they are outside its scope.
+ The act of running the Program is not restricted, and the
+ output from the Program is covered only if its contents
+ constitute a work based on the Program (independent of having
+ been made by running the Program). Whether that is true
+ depends on what the Program does.
+
+ 2. You may copy and distribute verbatim copies of the Program's
+ source code as you receive it, in any medium, provided that you
+ conspicuously and appropriately publish on each copy an
+ appropriate copyright notice and disclaimer of warranty; keep
+ intact all the notices that refer to this License and to the
+ absence of any warranty; and give any other recipients of the
+ Program a copy of this License along with the Program.
+
+ You may charge a fee for the physical act of transferring a
+ copy, and you may at your option offer warranty protection in
+ exchange for a fee.
+
+ 3. You may modify your copy or copies of the Program or any portion
+ of it, thus forming a work based on the Program, and copy and
+ distribute such modifications or work under the terms of
+ Section 1 above, provided that you also meet all of these
+ conditions:
+
+ 1. You must cause the modified files to carry prominent
+ notices stating that you changed the files and the date of
+ any change.
+
+ 2. You must cause any work that you distribute or publish,
+ that in whole or in part contains or is derived from the
+ Program or any part thereof, to be licensed as a whole at
+ no charge to all third parties under the terms of this
+ License.
+
+ 3. If the modified program normally reads commands
+ interactively when run, you must cause it, when started
+ running for such interactive use in the most ordinary way,
+ to print or display an announcement including an
+ appropriate copyright notice and a notice that there is no
+ warranty (or else, saying that you provide a warranty) and
+ that users may redistribute the program under these
+ conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive
+ but does not normally print such an announcement, your
+ work based on the Program is not required to print an
+ announcement.)
+
+ These requirements apply to the modified work as a whole. If
+ identifiable sections of that work are not derived from the
+ Program, and can be reasonably considered independent and
+ separate works in themselves, then this License, and its terms,
+ do not apply to those sections when you distribute them as
+ separate works. But when you distribute the same sections as
+ part of a whole which is a work based on the Program, the
+ distribution of the whole must be on the terms of this License,
+ whose permissions for other licensees extend to the entire
+ whole, and thus to each and every part regardless of who wrote
+ it.
+
+ Thus, it is not the intent of this section to claim rights
+ or contest your rights to work written entirely by you; rather,
+ the intent is to exercise the right to control the distribution
+ of derivative or collective works based on the Program.
+
+ In addition, mere aggregation of another work not based on
+ the Program with the Program (or with a work based on the
+ Program) on a volume of a storage or distribution medium does
+ not bring the other work under the scope of this License.
+
+ 4. You may copy and distribute the Program (or a work based on it,
+ under Section 2) in object code or executable form under the
+ terms of Sections 1 and 2 above provided that you also do one
+ of the following:
+
+ 1. Accompany it with the complete corresponding
+ machine-readable source code, which must be distributed
+ under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ 2. Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than
+ your cost of physically performing source distribution, a
+ complete machine-readable copy of the corresponding source
+ code, to be distributed under the terms of Sections 1 and
+ 2 above on a medium customarily used for software
+ interchange; or,
+
+ 3. Accompany it with the information you received as to the
+ offer to distribute corresponding source code. (This
+ alternative is allowed only for noncommercial distribution
+ and only if you received the program in object code or
+ executable form with such an offer, in accord with
+ Subsection b above.)
+
+ The source code for a work means the preferred form of the
+ work for making modifications to it. For an executable work,
+ complete source code means all the source code for all modules
+ it contains, plus any associated interface definition files,
+ plus the scripts used to control compilation and installation
+ of the executable. However, as a special exception, the source
+ code distributed need not include anything that is normally
+ distributed (in either source or binary form) with the major
+ components (compiler, kernel, and so on) of the operating
+ system on which the executable runs, unless that component
+ itself accompanies the executable.
+
+ If distribution of executable or object code is made by
+ offering access to copy from a designated place, then offering
+ equivalent access to copy the source code from the same place
+ counts as distribution of the source code, even though third
+ parties are not compelled to copy the source along with the
+ object code.
+
+ 5. You may not copy, modify, sublicense, or distribute the Program
+ except as expressly provided under this License. Any attempt
+ otherwise to copy, modify, sublicense or distribute the Program
+ is void, and will automatically terminate your rights under
+ this License. However, parties who have received copies, or
+ rights, from you under this License will not have their
+ licenses terminated so long as such parties remain in full
+ compliance.
+
+ 6. You are not required to accept this License, since you have not
+ signed it. However, nothing else grants you permission to
+ modify or distribute the Program or its derivative works.
+ These actions are prohibited by law if you do not accept this
+ License. Therefore, by modifying or distributing the Program
+ (or any work based on the Program), you indicate your
+ acceptance of this License to do so, and all its terms and
+ conditions for copying, distributing or modifying the Program
+ or works based on it.
+
+ 7. Each time you redistribute the Program (or any work based on the
+ Program), the recipient automatically receives a license from
+ the original licensor to copy, distribute or modify the Program
+ subject to these terms and conditions. You may not impose any
+ further restrictions on the recipients' exercise of the rights
+ granted herein. You are not responsible for enforcing
+ compliance by third parties to this License.
+
+ 8. If, as a consequence of a court judgment or allegation of patent
+ infringement or for any other reason (not limited to patent
+ issues), conditions are imposed on you (whether by court order,
+ agreement or otherwise) that contradict the conditions of this
+ License, they do not excuse you from the conditions of this
+ License. If you cannot distribute so as to satisfy
+ simultaneously your obligations under this License and any
+ other pertinent obligations, then as a consequence you may not
+ distribute the Program at all. For example, if a patent
+ license would not permit royalty-free redistribution of the
+ Program by all those who receive copies directly or indirectly
+ through you, then the only way you could satisfy both it and
+ this License would be to refrain entirely from distribution of
+ the Program.
+
+ If any portion of this section is held invalid or
+ unenforceable under any particular circumstance, the balance of
+ the section is intended to apply and the section as a whole is
+ intended to apply in other circumstances.
+
+ It is not the purpose of this section to induce you to
+ infringe any patents or other property right claims or to
+ contest validity of any such claims; this section has the sole
+ purpose of protecting the integrity of the free software
+ distribution system, which is implemented by public license
+ practices. Many people have made generous contributions to the
+ wide range of software distributed through that system in
+ reliance on consistent application of that system; it is up to
+ the author/donor to decide if he or she is willing to
+ distribute software through any other system and a licensee
+ cannot impose that choice.
+
+ This section is intended to make thoroughly clear what is
+ believed to be a consequence of the rest of this License.
+
+ 9. If the distribution and/or use of the Program is restricted in
+ certain countries either by patents or by copyrighted
+ interfaces, the original copyright holder who places the
+ Program under this License may add an explicit geographical
+ distribution limitation excluding those countries, so that
+ distribution is permitted only in or among countries not thus
+ excluded. In such case, this License incorporates the
+ limitation as if written in the body of this License.
+
+ 10. The Free Software Foundation may publish revised and/or new
+ versions of the General Public License from time to time. Such
+ new versions will be similar in spirit to the present version,
+ but may differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If
+ the Program specifies a version number of this License which
+ applies to it and "any later version", you have the option of
+ following the terms and conditions either of that version or of
+ any later version published by the Free Software Foundation.
+ If the Program does not specify a version number of this
+ License, you may choose any version ever published by the Free
+ Software Foundation.
+
+ 11. If you wish to incorporate parts of the Program into other free
+ programs whose distribution conditions are different, write to
+ the author to ask for permission. For software which is
+ copyrighted by the Free Software Foundation, write to the Free
+ Software Foundation; we sometimes make exceptions for this.
+ Our decision will be guided by the two goals of preserving the
+ free status of all derivatives of our free software and of
+ promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 12. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
+ WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE
+ LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
+ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS
+ WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE
+ COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 13. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+ WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY
+ MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE
+ LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
+ INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
+ INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS
+ OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE
+ WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY
+ HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+Appendix: How to Apply These Terms to Your New Programs
+=======================================================
+
+ If you develop a new program, and you want it to be of the
+greatest possible use to the public, the best way to achieve this is
+to make it free software which everyone can redistribute and change
+under these terms.
+
+ To do so, attach the following notices to the program. It is
+safest to attach them to the start of each source file to most
+effectively convey the exclusion of warranty; and each file should
+have at least the "copyright" line and a pointer to where the full
+notice is found.
+
+ ONE LINE TO GIVE THE PROGRAM'S NAME AND A BRIEF IDEA OF WHAT IT DOES.
+ Copyright (C) 19YY NAME OF AUTHOR
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Also add information on how to contact you by electronic and
+paper mail.
+
+ If the program is interactive, make it output a short notice like
+this when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19YY NAME OF AUTHOR
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+ The hypothetical commands `show w' and `show c' should show the
+appropriate parts of the General Public License. Of course, the
+commands you use may be called something other than `show w' and
+`show c'; they could even be mouse-clicks or menu items--whatever
+suits your program.
+
+ You should also get your employer (if you work as a programmer)
+or your school, if any, to sign a "copyright disclaimer" for the
+program, if necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ SIGNATURE OF TY COON, 1 April 1989
+ Ty Coon, President of Vice
+
+ This General Public License does not permit incorporating your
+program into proprietary programs. If your program is a subroutine
+library, you may consider it more useful to permit linking
+proprietary applications with the library. If this is what you want
+to do, use the GNU Library General Public License instead of this
+License.
+
+
+File: pcl-cvs, Node: Installation, Next: About pcl-cvs, Prev: Copying, Up: Top
+
+Installation
+************
+
+ This section describes the installation of pcl-cvs, the GNU Emacs
+CVS front-end. You should install not only the elisp files
+themselves, but also the on-line documentation so that your users
+will know how to use it. You can create typeset documentation from
+the file `pcl-cvs.texinfo' as well as an on-line info file. The
+following steps are also described in the file `INSTALL' in the
+source directory.
+
+* Menu:
+
+* Pcl-cvs installation:: How to install pcl-cvs on your system.
+* On-line manual installation:: How to install the on-line manual.
+* Typeset manual installation:: How to create typeset documentation
+ about pcl-cvs.
+
+
+File: pcl-cvs, Node: Pcl-cvs installation, Next: On-line manual installation, Prev: Installation, Up: Installation
+
+Installation of the pcl-cvs program
+===================================
+
+ 1. Edit the file `Makefile' to reflect the situation at your site.
+ The only things you have to change is the definition of
+ `lispdir' and `infodir'. The elisp files will be copied to
+ `lispdir', and the info file to `infodir'.
+
+ 2. Configure pcl-cvs.el
+
+ There are a couple of paths that you have to check to make
+ sure that they match you system. They appear early in the file
+ pcl-cvs.el.
+
+ *NOTE:* If your system is running emacs 18.57 or earlier
+ you MUST uncomment the line that says:
+
+ (setq delete-exited-processes nil)
+
+ Setting `delete-exited-processes' to `nil' works around a bug
+ in emacs that causes it to dump core. The bug was fixed in
+ emacs 18.58.
+
+ 3. Type `make install' in the source directory. This will
+ byte-compile all `.el' files and copy both the `.el' and the
+ `.elc' into the directory you specified in step 1.
+
+ If you don't want to install the `.el' files but only the
+ `.elc' files (the byte-compiled files), you can type ``make
+ install_elc'' instead of ``make install''.
+
+ If you only want to create the compiled elisp files, but
+ don't want to install them, you can type `make elcfiles'
+ instead. This is what happens if you only type `make' without
+ parameters.
+
+ 4. Edit the file `default.el' in your emacs lisp directory (usually
+ `/usr/gnu/emacs/lisp' or something similar) and enter the
+ contents of the file `pcl-cvs-startup.el' into it. It contains
+ a couple of `auto-load's that facilitates the use of pcl-cvs.
+
+
+File: pcl-cvs, Node: On-line manual installation, Next: Typeset manual installation, Prev: Pcl-cvs installation, Up: Installation
+
+Installation of the on-line manual.
+===================================
+
+ 1. Create the info file `pcl-cvs' from `pcl-cvs.texinfo' by typing
+ `make info'. If you don't have the program `makeinfo' you can
+ get it by anonymous ftp from e.g. `ftp.gnu.ai.mit.edu' as
+ `pub/gnu/texinfo-2.14.tar.Z' (there might be a newer version
+ there when you read this), or you could use the preformatted
+ info file `pcl-cvs.info' that is included in the distribution
+ (type `cp pcl-cvs.info pcl-cvs').
+
+ 2. Move the info file `pcl-cvs' to your standard info directory.
+ This might be called something like `/usr/gnu/emacs/info'.
+
+ 3. Edit the file `dir' in the info directory and enter one line to
+ contain a pointer to the info file `pcl-cvs'. The line can, for
+ instance, look like this:
+
+ * Pcl-cvs: (pcl-cvs). An Emacs front-end to CVS.
+
+
+File: pcl-cvs, Node: Typeset manual installation, Prev: On-line manual installation, Up: Installation
+
+How to make typeset documentation from pcl-cvs.texinfo
+======================================================
+
+ If you have TeX installed at your site, you can make a typeset
+manual from `pcl-cvs.texinfo'.
+
+ 1. Run TeX by typing ``make pcl-cvs.dvi''. You will not get the
+ indices unless you have the `texindex' program.
+
+ 2. Convert the resulting device independent file `pcl-cvs.dvi' to a
+ form which your printer can output and print it. If you have a
+ postscript printer there is a program, `dvi2ps', which does.
+ There is also a program which comes together with TeX, `dvips',
+ which you can use.
+
+
+File: pcl-cvs, Node: About pcl-cvs, Next: Getting started, Prev: Installation, Up: Top
+
+About pcl-cvs
+*************
+
+ Pcl-cvs is a front-end to CVS version 1.3. It integrates the most
+frequently used CVS commands into emacs.
+
+* Menu:
+
+* Contributors:: Contributors to pcl-cvs.
+* Archives:: Where can I get a copy of Pcl-Cvs?
+
+
+File: pcl-cvs, Node: Contributors, Next: Archives, Prev: About pcl-cvs, Up: About pcl-cvs
+
+Contributors to pcl-cvs
+=======================
+
+ Contributions to the package are welcome. I have limited time to
+work on this project, but I will gladly add any code that you
+contribute to me to this package (*note Reporting bugs and ideas::.).
+
+ The following persons have made contributions to pcl-cvs.
+
+ * Brian Berliner wrote CVS, together with some other contributors.
+ Without his work on CVS this package would be useless...
+
+ * Per Cederqvist wrote most of the otherwise unattributed
+ functions in pcl-cvs as well as all documentation.
+
+ * Inge Wallin (`inge@lysator.liu.se') wrote the skeleton to
+ `pcl-cvs.texinfo', and gave useful comments on it. He also
+ wrote the files `elib-node.el' and `compile-all.el'. The file
+ `cookie.el' was inspired by Inge.
+
+ * Linus Tolke (`linus@lysator.liu.se') contributed useful comments
+ on both the functionality and the documentation.
+
+
+File: pcl-cvs, Node: Archives, Prev: Contributors, Up: About pcl-cvs
+
+Where can I get pcl-cvs?
+========================
+
+ This release of pcl-cvs is included in the CVS 1.3 distribution.
+However, since pcl-cvs has had less time to mature (the first line of
+code was written less than a year ago) it is likely that there will
+be a new release of pcl-cvs before the next release of CVS.
+
+ The latest release of pcl-cvs can be fetched via anonymous ftp
+from `ftp.lysator.liu.se', (IP no. 130.236.254.1) in the directory
+`pub/emacs'. If you don't live in Scandinavia you should probably
+check with archie to see if there is a site closer to you that
+archives pcl-cvs.
+
+ New releases will be announced to appropriate newsgroups. If you
+send your email address to me I will add you to my list of people to
+mail when I make a new release.
+
+
+File: pcl-cvs, Node: Getting started, Next: Buffer contents, Prev: About pcl-cvs, Up: Top
+
+Getting started
+***************
+
+ This document assumes that you know what CVS is, and that you at
+least knows the fundamental concepts of CVS. If that is not the
+case you should read the man page for CVS.
+
+ Pcl-cvs is only useful once you have checked out a module. So
+before you invoke it you must have a copy of a module somewhere in
+the file system.
+
+ You invoke pcl-cvs by typing `M-x pcl-cvs RET'. If your emacs
+responds with `[No match]' your system administrator has not
+installed pcl-cvs properly. Try `M-x load-library RET pcl-cvs RET'.
+If that also fails - talk to your root. If it succeeds you might put
+this line in your `.emacs' file so that you don't have to type the
+`load-library' command every time you wish to use pcl-cvs:
+
+ (autoload 'cvs-update "pcl-cvs" nil t)
+
+ The function `cvs-update' will ask for a directory. The command
+`cvs update' will be run in that directory. (It should contain
+files that have been checked out from a CVS archive.) The output
+from `cvs' will be parsed and presented in a table in a buffer called
+`*cvs*'. It might look something like this:
+
+ PCL-CVS release 1.02.
+
+ In directory /users/ceder/FOO/test:
+ Updated bar
+ Updated file.txt
+ Modified ci namechange
+ Updated newer
+
+ In directory /users/ceder/FOO/test/sub:
+ Modified ci ChangeLog
+ ---------- End -----
+
+ In this example the three files (`bar', `file.txt' and `newer')
+that are marked with `Updated' have been copied from the CVS
+repository to `/users/ceder/FOO/test/' since someone else have
+checked in newer versions of them. Two files (`namechange' and
+`sub/ChangeLog') have been modified locally, and needs to be checked
+in.
+
+ You can move the cursor up and down in the buffer with `C-n' and
+`C-p' or `n' and `p'. If you press `c' on one of the `Modified'
+files that file will be checked in to the CVS repository. *Note
+Committing changes::. You can press `x' to get rid of the
+"uninteresting" files that have only been `Updated' (and don't
+require any further action from you).
+
+ You can also easily get a `diff' between your modified file and
+the base version that you started from, and you can get the output
+from `cvs log' and `cvs status' on the listed files simply by
+pressing a key (*note Getting info about files::.).
+
+
+File: pcl-cvs, Node: Buffer contents, Next: Commands, Prev: Getting started, Up: Top
+
+Buffer contents
+***************
+
+ The display contains four columns. They contain, from left to
+right:
+
+ * An asterisk when the file is "marked" (*note Selected files::.).
+
+ * The status of the file. See *Note File status::, for more
+ information.
+
+ * A "need to be checked in"-marker (`ci').
+
+ * The file name.
+
+* Menu:
+
+* File status:: The meaning of the second field.
+* Selected files:: How selection works.
+
+
+File: pcl-cvs, Node: File status, Next: Selected files, Prev: Buffer contents, Up: Buffer contents
+
+File status
+===========
+
+ The `file status' field can have the following values:
+
+`Updated'
+ The file was brought up to date with respect to the repository.
+ This is done for any file that exists in the repository but
+ not in your source, and for files that you haven't changed but
+ are not the most recent versions available in the repository.
+
+`Modified'
+ The file is modified in your working directory, and there
+ was no modification to the same file in the repository.
+
+`Merged'
+ The file is modified in your working directory, and there were
+ modifications in the repository as well as in your copy, but
+ they were merged successfully, without conflict, in your
+ working directory.
+
+`Conflict'
+ A conflict was detected while trying to merge your changes to
+ FILE with changes from the source repository. FILE (the copy
+ in your working directory) is now the output of the `rcsmerge'
+ command on the two versions; an unmodified copy of your file is
+ also in your working directory, with the name `.#FILE.VERSION',
+ where VERSION is the RCS revision that your modified file
+ started from. *Note Viewing differences::, for more details.
+
+`Added'
+ The file has been added by you, but it still needs to be
+ checked in to the repository.
+
+`Removed'
+ The file has been removed by you, but it needs to be checked in
+ to the repository. You can resurrect it by typing `a' (*note
+ Adding and removing files::.).
+
+`Unknown'
+ A file that was detected in your directory, but that neither
+ appears in the repository, nor is present on the list of files
+ that CVS should ignore.
+
+ There are also a few special cases, that rarely occur, which have
+longer strings in the fields:
+
+`Removed from repository'
+ The file has been removed from your directory since someone has
+ removed it from the repository. (It is still present in the
+ Attic directory, so no permanent loss has occurred). This,
+ unlike the other entries in this table, is not an error
+ condition.
+
+`Removed from repository, changed by you'
+ You have modified a file that someone have removed from the
+ repository. You can correct this situation by removing the
+ file manually (see *note Adding and removing files::.).
+
+`Removed by you, changed in repository'
+ You have removed a file, and before you committed the removal
+ someone committed a change to that file. You could use `a' to
+ resurrect the file (see *note Adding and removing files::.).
+
+`Move away FILE - it is in the way'
+ For some reason CVS does not like the file FILE. Rename or
+ remove it.
+
+`This repository is missing! Remove this dir manually.'
+ It is impossible to remove a directory in the CVS repository in
+ a clean way. Someone have tried to remove one, and CVS gets
+ confused. Remove your copy of the directory.
+
+
+File: pcl-cvs, Node: Selected files, Prev: File status, Up: Buffer contents
+
+Selected files
+==============
+
+ Many of the commands works on the current set of "selected" files.
+
+ * If there are any files that are marked they constitute the set
+ of selected files.
+
+ * Otherwise, if the cursor points to a file, that file is the
+ selected file.
+
+ * Otherwise, if the cursor points to a directory, all the files
+ in that directory that appears in the buffer are the selected
+ files.
+
+ This scheme might seem a little complicated, but once one get
+used to it, it is quite powerful.
+
+ *Note Marking files:: tells how you mark and unmark files.
+
+
+File: pcl-cvs, Node: Commands, Next: Customization, Prev: Buffer contents, Up: Top
+
+Commands
+********
+
+ The nodes in this menu contains explanations about all the
+commands that you can use in pcl-cvs. They are grouped together by
+type.
+
+* Menu:
+
+* Updating the directory:: Commands to update the local directory
+* Movement commands:: How to move up and down in the buffer
+* Marking files:: How to mark files that other commands
+ will later operate on.
+* Committing changes:: Checking in your modifications to the
+ CVS repository.
+* Editing files:: Loading files into Emacs.
+* Getting info about files:: Display the log and status of files.
+* Adding and removing files:: Adding and removing files
+* Removing handled entries:: Uninteresting lines can easily be removed.
+* Ignoring files:: Telling CVS to ignore generated files.
+* Viewing differences:: Commands to `diff' different versions.
+
+
+File: pcl-cvs, Node: Updating the directory, Next: Movement commands, Prev: Commands, Up: Commands
+
+Updating the directory
+======================
+
+`M-x cvs-update'
+ Run a `cvs update' command. You will be asked for the
+ directory in which the `cvs update' will be run. The output
+ will be parsed by pcl-cvs, and the result printed in the
+ `*cvs*' buffer (see *note Buffer contents::. for a description
+ of the contents).
+
+ By default, `cvs-update' will descend recursively into
+ subdirectories. You can avoid that behavior by giving a prefix
+ argument to it (e.g., by typing `C-u M-x cvs-update RET').
+
+ All other commands in pcl-cvs requires that you have a `*cvs*'
+ buffer. This is the command that you use to get one.
+
+`g'
+ This will run `cvs update' again. It will always use the same
+ buffer that was used with the previous `cvs update'. Give a
+ prefix argument to avoid descending into subdirectories. This
+ runs the command `cvs-update-no-prompt'.
+
+
+File: pcl-cvs, Node: Movement commands, Next: Marking files, Prev: Updating the directory, Up: Commands
+
+Movement Commands
+=================
+
+ You can use most normal Emacs commands to move forward and
+backward in the buffer. Some keys are rebound to functions that
+take advantage of the fact that the buffer is a pcl-cvs buffer:
+
+`SPC'
+`C-n'
+`n'
+ These keys move the cursor one file forward, towards the end of
+ the buffer (`cookie-next-cookie').
+
+`C-p'
+`p'
+ These keys move one file backward, towards the beginning of the
+ buffer (`cookie-previous-cookie').
+
+
+File: pcl-cvs, Node: Marking files, Next: Committing changes, Prev: Movement commands, Up: Commands
+
+Marking files
+=============
+
+ Pcl-cvs works on a set of "selected files" (*note Selected
+files::.). You can mark and unmark files with these commands:
+
+`m'
+ This marks the file that the cursor is positioned on. If the
+ cursor is positioned on a directory all files in that directory
+ will be marked. (`cvs-mark').
+
+`u'
+ Unmark the file that the cursor is positioned on. If the cursor
+ is on a directory, all files in that directory will be unmarked.
+ (`cvs-unmark').
+
+`M'
+ Mark *all* files in the buffer (`cvs-mark-all-files').
+
+`U'
+ Unmark *all* files (`cvs-unmark-all-files').
+
+`DEL'
+ Unmark the file on the previous line, and move point to that
+ line (`cvs-unmark-up').
+
+
+File: pcl-cvs, Node: Committing changes, Next: Editing files, Prev: Marking files, Up: Commands
+
+Committing changes
+==================
+
+`c'
+ All files that have a "need to be checked in"-marker (*note
+ Buffer contents::.) can be checked in with the `c' command. It
+ checks in all selected files (*note Selected files::.) (except
+ those who lack the "ci"-marker - they are ignored). Pressing
+ `c' causes `cvs-commit' to be run.
+
+ When you press `c' you will get a buffer called
+ `*cvs-commit-message*'. Enter the log message for the file(s)
+ in it. When you are ready you should press `C-c C-c' to
+ actually commit the files (using `cvs-edit-done').
+
+ Normally the `*cvs-commit-message*' buffer will retain the log
+ message from the previous commit, but if the variable
+ `cvs-erase-input-buffer' is set to a non-nil value the buffer
+ will be erased. Point and mark will always be located around
+ the entire buffer so that you can easily erase it with `C-w'
+ (`kill-region').
+
+
+File: pcl-cvs, Node: Editing files, Next: Getting info about files, Prev: Committing changes, Up: Commands
+
+Editing files
+=============
+
+ There are currently three commands that can be used to find a
+file (that is, load it into a buffer and start editing it there).
+These commands work on the line that the cursor is situated at.
+They ignore any marked files.
+
+`f'
+ Find the file that the cursor points to. Run `dired'
+
+ (*note Dired: (Emacs)Dired.)
+
+ if the cursor points to a directory (`cvs-find-file').
+
+`o'
+ Like `f', but use another window (`cvs-find-file-other-window').
+
+`A'
+ Invoke `add-change-log-entry-other-window' to edit a
+ `ChangeLog' file. The `ChangeLog' will be found in the
+ directory of the file the cursor points to.
+ (`cvs-add-change-log-entry-other-window').
+
+
+File: pcl-cvs, Node: Getting info about files, Next: Adding and removing files, Prev: Editing files, Up: Commands
+
+Getting info about files
+========================
+
+ Both of the following commands can be customized. *Note
+Customization::.
+
+`l'
+ Run `cvs log' on all selected files, and show the result in a
+ temporary buffer (`cvs-log').
+
+`s'
+ Run `cvs status' on all selected files, and show the result in a
+ temporary buffer (`cvs-status').
+
+
+File: pcl-cvs, Node: Adding and removing files, Next: Removing handled entries, Prev: Getting info about files, Up: Commands
+
+Adding and removing files
+=========================
+
+ The following commands are available to make it easy to add and
+remove files from the CVS repository.
+
+`a'
+ Add all selected files. This command can be used on `Unknown'
+ files (see *note File status::.). The status of the file will
+ change to `Added', and you will have to use `c' (`cvs-commit',
+ see *note Committing changes::.) to really add the file to the
+ repository.
+
+ This command can also be used on `Removed' files (before you
+ commit them) to resurrect them.
+
+ Selected files that are neither `Unknown' nor `Removed' will be
+ ignored by this command.
+
+ The command that is run is `cvs-add'.
+
+`r'
+ This command removes the selected files (after prompting for
+ confirmation). The files are `rm'ed from your directory and
+ (unless the status was `Unknown'; *note File status::.) they
+ will also be `cvs remove'd. If the files were `Unknown' they
+ will disappear from the buffer. Otherwise their status will
+ change to `Removed', and you must use `c' (`cvs-commit', *note
+ Committing changes::.) to commit the removal.
+
+ The command that is run is `cvs-remove-file'.
+
+
+File: pcl-cvs, Node: Removing handled entries, Next: Ignoring files, Prev: Adding and removing files, Up: Commands
+
+Removing handled entries
+========================
+
+`x'
+ This command allows you to remove all entries that you have
+ processed. More specifically, the lines for `Updated' files
+ (*note File status::. and files that have been checked in
+ (*note Committing changes::.) are removed from the buffer. If
+ a directory becomes empty the heading for that directory is
+ also removed. This makes it easier to get an overview of what
+ needs to be done.
+
+ The command is called `cvs-remove-handled'. If
+ `cvs-auto-remove-handled' is set to non-`nil' this will
+ automatically be performed after every commit.
+
+`C-k'
+ This command can be used for lines that `cvs-remove-handled'
+ would not delete, but that you want to delete
+ (`cvs-acknowledge').
+
+
+File: pcl-cvs, Node: Ignoring files, Next: Viewing differences, Prev: Removing handled entries, Up: Commands
+
+Ignoring files
+==============
+
+`i'
+ Arrange so that CVS will ignore the selected files. The file
+ names are added to the `.cvsignore' file in the corresponding
+ directory. If the `.cvsignore' doesn't exist it will be
+ created.
+
+ The `.cvsignore' file should normally be added to the
+ repository, but you could ignore it also if you like it better
+ that way.
+
+ This runs `cvs-ignore'.
+
+
+File: pcl-cvs, Node: Viewing differences, Prev: Ignoring files, Up: Commands
+
+Viewing differences
+===================
+
+`d'
+ Display a `cvs diff' between the selected files and the RCS
+ version that they are based on. *Note Customization::
+ describes how you can send flags to `cvs diff'. (The function
+ that does the job is `cvs-diff-cvs').
+
+`b'
+ If CVS finds a conflict while merging two versions of a file
+ (during a `cvs update', *note Updating the directory::.) it
+ will save the original file in a file called `.#FILE.VERSION'
+ where FILE is the name of the file, and VERSION is the RCS
+ version number that your file was based on.
+
+ With the `b' command you can run a `diff' on the files
+ `.#FILE.VERSION' and `FILE'. You can get a context- or Unidiff
+ by setting `cvs-diff-flags' - *note Customization::.. This
+ command only works on files that have status `Conflict' or
+ `Merged'. The name of the command is `cvs-diff-backup'.
+
+
+File: pcl-cvs, Node: Customization, Next: Future enhancements, Prev: Commands, Up: Top
+
+Customization
+*************
+
+ If you have an idea about any customization that would be handy
+but isn't present in this list, please tell me! *Note Reporting
+bugs and ideas:: for info on how to reach me.
+
+`cvs-erase-input-buffer'
+ If set to anything else than `nil' the edit buffer will be
+ erased before you write the log message (*note Committing
+ changes::.).
+
+`cvs-inhibit-copyright-message'
+ The copyright message that is displayed on startup can be
+ annoying after a while. Set this variable to `t' if you want
+ to get rid of it. (But don't set this to `t' in the system
+ defaults file - new users should see this message at least
+ once).
+
+`cvs-cvs-diff-flags'
+ A list of strings to pass as arguments to the `cvs diff'
+ program. This is used by `cvs-diff-cvs' (key `d', *note
+ Viewing differences::.). If you prefer the Unidiff format you
+ could add this line to your `.emacs' file:
+
+ (setq cvs-cvs-diff-flags '("-u"))
+
+`cvs-diff-flags'
+ Like `cvs-cvs-diff-flags', but passed to `diff'. This is used
+ by `cvs-diff-backup' (key `b', *note Viewing differences::.).
+
+`cvs-log-flags'
+ List of strings to send to `cvs log'. Used by `cvs-log' (key
+ `l', *note Getting info about files::.).
+
+`cvs-status-flags'
+ List of strings to send to `cvs status'. Used by `cvs-status'
+ (key `s', *note Getting info about files::.).
+
+`cvs-auto-remove-handled'
+ If this variable is set to any non-`nil' value
+ `cvs-remove-handled' will be called every time you check in
+ files, after the check-in is ready. *Note Removing handled
+ entries::.
+
+
+File: pcl-cvs, Node: Future enhancements, Next: Reporting bugs and ideas, Prev: Customization, Up: Top
+
+Future enhancements
+*******************
+
+ Pcl-cvs is still under development and needs a number of
+enhancements to be called complete. Here is my current wish-list
+for future releases of pcl-cvs:
+
+ * Dired support. I have an experimental `dired-cvs.el' that works
+ together with CVS 1.2. Unfortunately I wrote it on top of a
+ non-standard `dired.el', so it must be rewritten.
+
+ * It should be possible to run commands such as `cvs log', `cvs
+ status' and `cvs commit' directly from a buffer containing a
+ file, instead of having to `cvs-update'. If the directory
+ contains many files the `cvs-update' can take quite some time,
+ especially on a slow machine.
+
+ If you miss something in this wish-list, let me know! I don't
+promise that I will write it, but I will at least try to coordinate
+the efforts of making a good Emacs front end to CVS. See *Note
+Reporting bugs and ideas:: for information about how to reach me.
+
+
+File: pcl-cvs, Node: Reporting bugs and ideas, Next: Function and Variable Index, Prev: Future enhancements, Up: Top
+
+Reporting bugs and ideas
+************************
+
+ If you find a bug or misfeature, don't hesitate to tell me! Send
+email to `ceder@lysator.liu.se'.
+
+ If you have ideas for improvements, or if you have written some
+extensions to this package, I would like to hear from you. I hope
+that you find this package useful!
+
+
+File: pcl-cvs, Node: Function and Variable Index, Next: Concept Index, Prev: Reporting bugs and ideas, Up: Top
+
+Function and Variable Index
+***************************
+
+* Menu:
+
+* cookie-next-cookie: Movement commands.
+* cookie-previous-cookie: Movement commands.
+* cvs-acknowledge: Removing handled entries.
+* cvs-add: Adding and removing files.
+* cvs-add-change-log-entry-other-window: Editing files.
+* cvs-auto-remove-handled (variable): Customization.
+* cvs-commit: Committing changes.
+* cvs-cvs-diff-flags (variable): Customization.
+* cvs-diff-backup: Viewing differences.
+* cvs-diff-cvs: Viewing differences.
+* cvs-diff-flags (variable): Customization.
+* cvs-erase-input-buffer (variable): Committing changes.
+* cvs-erase-input-buffer (variable): Customization.
+* cvs-find-file: Editing files.
+* cvs-find-file-other-window: Editing files.
+* cvs-inhibit-copyright-message (variable): Customization.
+* cvs-log: Getting info about files.
+* cvs-log-flags (variable): Customization.
+* cvs-mark: Marking files.
+* cvs-mark-all-files: Marking files.
+* cvs-remove-file: Adding and removing files.
+* cvs-remove-handled: Removing handled entries.
+* cvs-status: Getting info about files.
+* cvs-status-flags (variable): Customization.
+* cvs-unmark: Marking files.
+* cvs-unmark-all-files: Marking files.
+* cvs-unmark-up: Marking files.
+* cvs-update: Updating the directory.
+* cvs-update-no-prompt: Updating the directory.
+
+
+File: pcl-cvs, Node: Concept Index, Next: Key Index, Prev: Function and Variable Index, Up: Top
+
+Concept Index
+*************
+
+* Menu:
+
+* About pcl-cvs: About pcl-cvs.
+* Active files: Selected files.
+* Added (file status): File status.
+* Adding files: Adding and removing files.
+* Archives: Archives.
+* Author, how to reach: Reporting bugs and ideas.
+* Authors: Contributors.
+* Automatically remove handled files: Customization.
+* Buffer contents: Buffer contents.
+* Bugs, how to report them: Reporting bugs and ideas.
+* Ci: Committing changes.
+* Commit buffer: Committing changes.
+* Committing changes: Committing changes.
+* Conflict (file status): File status.
+* Conflicts, how to resolve them: Viewing differences.
+* Context diff, how to get: Customization.
+* Contributors: Contributors.
+* Copyright message, getting rid of it: Customization.
+* Customization: Customization.
+* Deleting files: Adding and removing files.
+* Diff: Viewing differences.
+* Dired: Editing files.
+* Edit buffer: Committing changes.
+* Editing files: Editing files.
+* Email archives: Archives.
+* Email to the author: Reporting bugs and ideas.
+* Enhancements: Future enhancements.
+* Erasing commit message: Committing changes.
+* Erasing the input buffer: Customization.
+* Example run: Getting started.
+* Expunging uninteresting entries: Removing handled entries.
+* File selection: Selected files.
+* File status: File status.
+* Finding files: Editing files.
+* Ftp-sites: Archives.
+* Generating a typeset manual: Typeset manual installation.
+* Generating the on-line manual: On-line manual installation.
+* Getting pcl-cvs: Archives.
+* Getting rid of the Copyright message.: Customization.
+* Getting rid of uninteresting lines: Removing handled entries.
+* Getting status: Getting info about files.
+* Handled lines, removing them: Removing handled entries.
+* Info-file (how to generate): On-line manual installation.
+* Inhibiting the Copyright message.: Customization.
+* Installation: Installation.
+* Installation of elisp files: Pcl-cvs installation.
+* Installation of on-line manual: On-line manual installation.
+* Installation of typeset manual: Typeset manual installation.
+* Introduction: Getting started.
+* Invoking dired: Editing files.
+* Loading files: Editing files.
+* Log (RCS/cvs command): Getting info about files.
+* Manual installation (on-line): On-line manual installation.
+* Manual installation (typeset): Typeset manual installation.
+* Marked files: Selected files.
+* Marking files: Marking files.
+* Merged (file status): File status.
+* Modified (file status): File status.
+* Move away FILE - it is in the way (file status): File status.
+* Movement Commands: Movement commands.
+* On-line manual (how to generate): On-line manual installation.
+* Printing a manual: Typeset manual installation.
+* Putting files under CVS control: Adding and removing files.
+* Removed (file status): File status.
+* Removed by you, changed in repository (file status): File status.
+* Removed from repository (file status): File status.
+* Removed from repository, changed by you (file status): File status.
+* Removing files: Adding and removing files.
+* Removing uninteresting (processed) lines: Removing handled entries.
+* Reporting bugs and ideas: Reporting bugs and ideas.
+* Resurrecting files: Adding and removing files.
+* Selected files: Selected files.
+* Selecting files (commands to mark files): Marking files.
+* Sites: Archives.
+* Status (cvs command): Getting info about files.
+* TeX - generating a typeset manual: Typeset manual installation.
+* This repository is missing!... (file status): File status.
+* Unidiff, how to get: Customization.
+* Uninteresting entries, getting rid of them: Removing handled entries.
+* Unknown (file status): File status.
+* Updated (file status): File status.
+* Variables, list of all: Customization.
+* Viewing differences: Viewing differences.
+
+
+File: pcl-cvs, Node: Key Index, Prev: Concept Index, Up: Top
+
+Key Index
+*********
+
+* Menu:
+
+* A - add ChangeLog entry: Editing files.
+* C-k - remove selected entries: Removing handled entries.
+* C-n - Move down one file: Movement commands.
+* C-p - Move up one file: Movement commands.
+* DEL - unmark previous file: Marking files.
+* M - marking all files: Marking files.
+* SPC - Move down one file: Movement commands.
+* U - unmark all files: Marking files.
+* a - add a file: Adding and removing files.
+* b - diff backup file: Viewing differences.
+* c - commit files: Committing changes.
+* d - run cvs diff: Viewing differences.
+* f - find file or directory: Editing files.
+* g - Rerun cvs update: Updating the directory.
+* l - run cvs log: Getting info about files.
+* m - marking a file: Marking files.
+* n - Move down one file: Movement commands.
+* o - find file in other window: Editing files.
+* p - Move up on file: Movement commands.
+* r - remove a file: Adding and removing files.
+* s - run cvs status: Getting info about files.
+* u - unmark a file: Marking files.
+* x - remove processed entries: Removing handled entries.
+
+
+
+Tag Table:
+Node: Top1004
+Node: Copying3396
+Node: Installation22716
+Node: Pcl-cvs installation23507
+Node: On-line manual installation25291
+Node: Typeset manual installation26310
+Node: About pcl-cvs27048
+Node: Contributors27417
+Node: Archives28440
+Node: Getting started29287
+Node: Buffer contents31728
+Node: File status32277
+Node: Selected files35303
+Node: Commands35976
+Node: Updating the directory37018
+Node: Movement commands38043
+Node: Marking files38629
+Node: Committing changes39456
+Node: Editing files40502
+Node: Getting info about files41335
+Node: Adding and removing files41805
+Node: Removing handled entries43145
+Node: Ignoring files44058
+Node: Viewing differences44593
+Node: Customization45595
+Node: Future enhancements47326
+Node: Reporting bugs and ideas48394
+Node: Function and Variable Index48842
+Node: Concept Index50743
+Node: Key Index55865
+
+End Tag Table
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.texinfo b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.texinfo
new file mode 100644
index 000000000000..5ad8db1ede47
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.texinfo
@@ -0,0 +1,1437 @@
+\input texinfo @c -*-texinfo-*-
+
+@comment pcl-cvs.texinfo,v 1.2 1992/04/07 20:49:23 berliner Exp
+@comment Documentation for the GNU Emacs CVS mode.
+@comment Copyright (C) 1992 Per Cederqvist
+
+@comment This file is part of the pcl-cvs distribution.
+
+@comment Pcl-cvs is free software; you can redistribute it and/or modify
+@comment it under the terms of the GNU General Public License as published by
+@comment the Free Software Foundation; either version 1, or (at your option)
+@comment any later version.
+
+@comment Pcl-cvs is distributed in the hope that it will be useful,
+@comment but WITHOUT ANY WARRANTY; without even the implied warranty of
+@comment MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+@comment GNU General Public License for more details.
+
+@comment You should have received a copy of the GNU General Public License
+@comment along with pcl-cvs; see the file COPYING. If not, write to
+@comment the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+@setfilename pcl-cvs
+@settitle Pcl-cvs - The Emacs Front-End to CVS
+@setchapternewpage on
+
+@ifinfo
+Copyright @copyright{} 1992 Per Cederqvist
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+section entitled ``GNU General Public License'' is included exactly as
+in the original, and provided that the entire resulting derived work is
+distributed under the terms of a permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that the section entitled ``GNU General Public License'' and
+this permission notice may be included in translations approved by the
+Free Software Foundation instead of in the original English.
+@end ifinfo
+
+@synindex vr fn
+@comment The titlepage section does not appear in the Info file.
+@titlepage
+@sp 4
+@comment The title is printed in a large font.
+@center @titlefont{User's Guide}
+@sp
+@center @titlefont{to}
+@sp
+@center @titlefont{pcl-cvs - the Emacs Front-End to CVS}
+@sp 2
+@center release 1.02
+@comment -release-
+@sp 3
+@center Per Cederqvist
+@sp 3
+@center last updated 29 Mar 1992
+@comment -date-
+
+@comment The following two commands start the copyright page
+@comment for the printed manual. This will not appear in the Info file.
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1992 Per Cederqvist
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+section entitled ``GNU General Public License'' is included exactly as
+in the original, and provided that the entire resulting derived work is
+distributed under the terms of a permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that the section entitled ``GNU General Public License'' and
+this permission notice may be included in translations approved by the
+Free Software Foundation instead of in the original English.
+@end titlepage
+
+@comment ================================================================
+@comment The real text starts here
+@comment ================================================================
+
+@node Top, Copying, (dir), (dir)
+@comment node-name, next, previous, up
+
+
+@ifinfo
+This info manual describes pcl-cvs which is a GNU Emacs front-end to
+CVS. It works with CVS version 1.3. This manual is updated to release
+1.02 of pcl-cvs.
+@end ifinfo
+@comment -release-
+
+@menu
+* Copying:: GNU General Public License
+* Installation:: How to install pcl-cvs on your system.
+* About pcl-cvs:: Authors and ftp sites.
+
+* Getting started:: An introduction with a walk-through example.
+* Buffer contents:: An explanation of the buffer contents.
+* Commands:: All commands, grouped by type.
+
+* Customization:: How you can tailor pcl-cvs to suit your needs.
+* Future enhancements:: Future enhancements of pcl-cvs.
+* Reporting bugs and ideas:: Where to report bugs.
+
+* Function and Variable Index:: List of functions and variables.
+* Concept Index:: List of concepts.
+* Key Index:: List of keystrokes.
+
+ --- The Detailed Node Listing ---
+
+Installation
+
+* Pcl-cvs installation:: How to install pcl-cvs on your system.
+* On-line manual installation:: How to install the on-line manual.
+* Typeset manual installation:: How to create typeset documentation
+ about pcl-cvs.
+
+About pcl-cvs
+
+* Contributors:: Contributors to pcl-cvs.
+* Archives:: Where can I get a copy of Pcl-Cvs?
+
+Buffer contents
+
+* File status:: The meaning of the second field.
+* Selected files:: How selection works.
+
+Commands
+
+* Updating the directory:: Commands to update the local directory
+* Movement commands:: How to move up and down in the buffer
+* Marking files:: How to mark files that other commands
+ will later operate on.
+* Committing changes:: Checking in your modifications to the
+ CVS repository.
+* Editing files:: Loading files into Emacs.
+* Getting info about files:: Display the log and status of files.
+* Adding and removing files:: Adding and removing files
+* Removing handled entries:: Uninteresting lines can easily be removed.
+* Ignoring files:: Telling CVS to ignore generated files.
+* Viewing differences:: Commands to @samp{diff} different versions.
+@end menu
+
+@node Copying, Installation, Top, Top
+@unnumbered GNU GENERAL PUBLIC LICENSE
+@center Version 2, June 1991
+
+@display
+Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc.
+675 Mass Ave, Cambridge, MA 02139, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+@end display
+
+@unnumberedsec Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software---to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+@iftex
+@unnumberedsec TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end iftex
+@ifinfo
+@center TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end ifinfo
+
+@enumerate
+@item
+This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The ``Program'', below,
+refers to any such program or work, and a ``work based on the Program''
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term ``modification''.) Each licensee is addressed as ``you''.
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+@item
+You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+@item
+You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+@enumerate a
+@item
+You must cause the modified files to carry prominent notices
+stating that you changed the files and the date of any change.
+
+@item
+You must cause any work that you distribute or publish, that in
+whole or in part contains or is derived from the Program or any
+part thereof, to be licensed as a whole at no charge to all third
+parties under the terms of this License.
+
+@item
+If the modified program normally reads commands interactively
+when run, you must cause it, when started running for such
+interactive use in the most ordinary way, to print or display an
+announcement including an appropriate copyright notice and a
+notice that there is no warranty (or else, saying that you provide
+a warranty) and that users may redistribute the program under
+these conditions, and telling the user how to view a copy of this
+License. (Exception: if the Program itself is interactive but
+does not normally print such an announcement, your work based on
+the Program is not required to print an announcement.)
+@end enumerate
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+@item
+You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+@enumerate a
+@item
+Accompany it with the complete corresponding machine-readable
+source code, which must be distributed under the terms of Sections
+1 and 2 above on a medium customarily used for software interchange; or,
+
+@item
+Accompany it with a written offer, valid for at least three
+years, to give any third party, for a charge no more than your
+cost of physically performing source distribution, a complete
+machine-readable copy of the corresponding source code, to be
+distributed under the terms of Sections 1 and 2 above on a medium
+customarily used for software interchange; or,
+
+@item
+Accompany it with the information you received as to the offer
+to distribute corresponding source code. (This alternative is
+allowed only for noncommercial distribution and only if you
+received the program in object code or executable form with such
+an offer, in accord with Subsection b above.)
+@end enumerate
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+@item
+You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+@item
+You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+@item
+Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+@item
+If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+@item
+If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+@item
+The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and ``any
+later version'', you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+@item
+If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+@iftex
+@heading NO WARRANTY
+@end iftex
+@ifinfo
+@center NO WARRANTY
+@end ifinfo
+
+@item
+BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM ``AS IS'' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+@item
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+@end enumerate
+
+@iftex
+@heading END OF TERMS AND CONDITIONS
+@end iftex
+@ifinfo
+@center END OF TERMS AND CONDITIONS
+@end ifinfo
+
+@page
+@unnumberedsec Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the ``copyright'' line and a pointer to where the full notice is found.
+
+@smallexample
+@var{one line to give the program's name and a brief idea of what it does.}
+Copyright (C) 19@var{yy} @var{name of author}
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+@end smallexample
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+@smallexample
+Gnomovision version 69, Copyright (C) 19@var{yy} @var{name of author}
+Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+This is free software, and you are welcome to redistribute it
+under certain conditions; type `show c' for details.
+@end smallexample
+
+The hypothetical commands @samp{show w} and @samp{show c} should show
+the appropriate parts of the General Public License. Of course, the
+commands you use may be called something other than @samp{show w} and
+@samp{show c}; they could even be mouse-clicks or menu items---whatever
+suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a ``copyright disclaimer'' for the program, if
+necessary. Here is a sample; alter the names:
+
+@example
+Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+`Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+@var{signature of Ty Coon}, 1 April 1989
+Ty Coon, President of Vice
+@end example
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+@node Installation, About pcl-cvs, Copying, Top
+@comment node-name, next, previous, up
+@chapter Installation
+@cindex Installation
+
+This section describes the installation of pcl-cvs, the GNU Emacs CVS
+front-end. You should install not only the elisp files themselves, but
+also the on-line documentation so that your users will know how to use
+it. You can create typeset documentation from the file
+@file{pcl-cvs.texinfo} as well as an on-line info file. The following
+steps are also described in the file @file{INSTALL} in the source
+directory.
+
+@menu
+* Pcl-cvs installation:: How to install pcl-cvs on your system.
+* On-line manual installation:: How to install the on-line manual.
+* Typeset manual installation:: How to create typeset documentation
+ about pcl-cvs.
+@end menu
+
+@node Pcl-cvs installation, On-line manual installation, Installation, Installation
+@comment node-name, next, previous, up
+@section Installation of the pcl-cvs program
+@cindex Installation of elisp files
+
+@enumerate
+@item
+Edit the file @file{Makefile} to reflect the situation at your site.
+The only things you have to change is the definition of @code{lispdir}
+and @code{infodir}. The elisp files will be copied to @code{lispdir},
+and the info file to @code{infodir}.
+
+@item
+Configure pcl-cvs.el
+
+There are a couple of paths that you have to check to make sure that
+they match you system. They appear early in the file pcl-cvs.el.
+
+@strong{NOTE:} If your system is running emacs 18.57 or earlier you MUST
+uncomment the line that says:
+
+@example
+(setq delete-exited-processes nil)
+@end example
+
+Setting @code{delete-exited-processes} to @code{nil} works around a bug
+in emacs that causes it to dump core. The bug was fixed in emacs
+18.58.@refill
+
+@item
+Type @samp{make install} in the source directory. This will
+byte-compile all @file{.el} files and copy both the @file{.el} and the
+@file{.elc} into the directory you specified in step 1.
+
+If you don't want to install the @file{.el} files but only the
+@file{.elc} files (the byte-compiled files), you can type `@samp{make
+install_elc}' instead of `@samp{make install}'.
+
+If you only want to create the compiled elisp files, but don't want to
+install them, you can type @samp{make elcfiles} instead. This is what
+happens if you only type @samp{make} without parameters.
+
+@item
+Edit the file @file{default.el} in your emacs lisp directory (usually
+@file{/usr/gnu/emacs/lisp} or something similar) and enter the contents
+of the file @file{pcl-cvs-startup.el} into it. It contains a couple of
+@code{auto-load}s that facilitates the use of pcl-cvs.
+
+@end enumerate
+
+@node On-line manual installation, Typeset manual installation, Pcl-cvs installation, Installation
+@comment node-name, next, previous, up
+@section Installation of the on-line manual.
+@cindex Manual installation (on-line)
+@cindex Installation of on-line manual
+@cindex Generating the on-line manual
+@cindex On-line manual (how to generate)
+@cindex Info-file (how to generate)
+
+@enumerate
+@item
+Create the info file @file{pcl-cvs} from @file{pcl-cvs.texinfo} by
+typing @samp{make info}. If you don't have the program @samp{makeinfo}
+you can get it by anonymous ftp from e.g. @samp{ftp.gnu.ai.mit.edu} as
+@file{pub/gnu/texinfo-2.14.tar.Z} (there might be a newer version there
+when you read this), or you could use the preformatted info file
+@file{pcl-cvs.info} that is included in the distribution (type
+@samp{cp pcl-cvs.info pcl-cvs}).@refill
+
+@item
+Move the info file @file{pcl-cvs} to your standard info directory.
+This might be called something like @file{/usr/gnu/emacs/info}.@refill
+
+@item
+Edit the file @file{dir} in the info directory and enter one line to
+contain a pointer to the info file @file{pcl-cvs}. The line can, for
+instance, look like this:@refill
+
+@example
+* Pcl-cvs: (pcl-cvs). An Emacs front-end to CVS.
+@end example
+@end enumerate
+
+@node Typeset manual installation, , On-line manual installation, Installation
+@comment node-name, next, previous, up
+@section How to make typeset documentation from pcl-cvs.texinfo
+@cindex Manual installation (typeset)
+@cindex Installation of typeset manual
+@cindex Printing a manual
+@cindex TeX - generating a typeset manual
+@cindex Generating a typeset manual
+
+If you have @TeX{} installed at your site, you can make a typeset manual
+from @file{pcl-cvs.texinfo}.
+
+@enumerate
+@item
+Run @TeX{} by typing `@samp{make pcl-cvs.dvi}'. You will not get the
+indices unless you have the @code{texindex} program.
+
+@item
+Convert the resulting device independent file @file{pcl-cvs.dvi} to a
+form which your printer can output and print it. If you have a
+postscript printer there is a program, @code{dvi2ps}, which does. There
+is also a program which comes together with @TeX{}, @code{dvips}, which
+you can use.
+
+@end enumerate
+
+@node About pcl-cvs, Getting started, Installation, Top
+@comment node-name, next, previous, up
+@chapter About pcl-cvs
+@cindex About pcl-cvs
+
+Pcl-cvs is a front-end to CVS version 1.3. It integrates the most
+frequently used CVS commands into emacs.
+
+@menu
+* Contributors:: Contributors to pcl-cvs.
+* Archives:: Where can I get a copy of Pcl-Cvs?
+@end menu
+
+@node Contributors, Archives, About pcl-cvs, About pcl-cvs
+@comment node-name, next, previous, up
+@section Contributors to pcl-cvs
+@cindex Contributors
+@cindex Authors
+
+Contributions to the package are welcome. I have limited time to work
+on this project, but I will gladly add any code that you contribute to
+me to this package (@pxref{Reporting bugs and ideas}).
+
+The following persons have made contributions to pcl-cvs.
+
+@itemize @bullet
+@item
+Brian Berliner wrote CVS, together with some other contributors.
+Without his work on CVS this package would be useless@dots{}
+
+@item
+Per Cederqvist wrote most of the otherwise unattributed functions in
+pcl-cvs as well as all documentation.
+
+@item
+Inge Wallin (@samp{inge@@lysator.liu.se}) wrote the skeleton to
+@file{pcl-cvs.texinfo}, and gave useful comments on it. He also wrote
+the files @file{elib-node.el} and @file{compile-all.el}. The file
+@file{cookie.el} was inspired by Inge.@refill
+
+@item
+Linus Tolke (@samp{linus@@lysator.liu.se}) contributed useful comments
+on both the functionality and the documentation.@refill
+
+@end itemize
+
+
+@node Archives, , Contributors, About pcl-cvs
+@comment node-name, next, previous, up
+@section Where can I get pcl-cvs?
+@cindex Sites
+@cindex Archives
+@cindex Ftp-sites
+@cindex Getting pcl-cvs
+@cindex Email archives
+
+This release of pcl-cvs is included in the CVS 1.3 distribution.
+However, since pcl-cvs has had less time to mature (the first line of
+code was written less than a year ago) it is likely that there will be a
+new release of pcl-cvs before the next release of CVS.
+
+The latest release of pcl-cvs can be fetched via anonymous ftp from
+@code{ftp.lysator.liu.se}, (IP no. 130.236.254.1) in the directory
+@code{pub/emacs}. If you don't live in Scandinavia you should probably
+check with archie to see if there is a site closer to you that archives
+pcl-cvs.
+
+New releases will be announced to appropriate newsgroups. If you send
+your email address to me I will add you to my list of people to mail
+when I make a new release.
+
+@node Getting started, Buffer contents, About pcl-cvs, Top
+@comment node-name, next, previous, up
+@chapter Getting started
+@cindex Introduction
+@cindex Example run
+
+This document assumes that you know what CVS is, and that you at least
+knows the fundamental concepts of CVS. If that is not the case you
+should read the man page for CVS.
+
+Pcl-cvs is only useful once you have checked out a module. So before
+you invoke it you must have a copy of a module somewhere in the file
+system.
+
+You invoke pcl-cvs by typing @kbd{M-x pcl-cvs RET}. If your emacs
+responds with @samp{[No match]} your system administrator has not
+installed pcl-cvs properly. Try @kbd{M-x load-library RET pcl-cvs RET}.
+If that also fails - talk to your root. If it succeeds you might put
+this line in your @file{.emacs} file so that you don't have to type the
+@samp{load-library} command every time you wish to use pcl-cvs:
+
+@example
+(autoload 'cvs-update "pcl-cvs" nil t)
+@end example
+
+The function @code{cvs-update} will ask for a directory. The command
+@samp{cvs update} will be run in that directory. (It should contain
+files that have been checked out from a CVS archive.) The output from
+@code{cvs} will be parsed and presented in a table in a buffer called
+@samp{*cvs*}. It might look something like this:
+
+@example
+PCL-CVS release 1.02.
+@comment -release-
+
+In directory /users/ceder/FOO/test:
+ Updated bar
+ Updated file.txt
+ Modified ci namechange
+ Updated newer
+
+In directory /users/ceder/FOO/test/sub:
+ Modified ci ChangeLog
+---------- End -----
+@end example
+
+In this example the three files (@file{bar}, @file{file.txt} and
+@file{newer}) that are marked with @samp{Updated} have been copied from
+the CVS repository to @file{/users/ceder/FOO/test/} since someone else
+have checked in newer versions of them. Two files (@file{namechange}
+and @file{sub/ChangeLog}) have been modified locally, and needs to be
+checked in.
+
+You can move the cursor up and down in the buffer with @kbd{C-n} and
+@kbd{C-p} or @kbd{n} and @kbd{p}. If you press @kbd{c} on one of the
+@samp{Modified} files that file will be checked in to the CVS
+repository. @xref{Committing changes}. You can press @kbd{x} to get rid
+of the "uninteresting" files that have only been @samp{Updated} (and
+don't require any further action from you).@refill
+
+You can also easily get a @samp{diff} between your modified file and the
+base version that you started from, and you can get the output from
+@samp{cvs log} and @samp{cvs status} on the listed files simply by
+pressing a key (@pxref{Getting info about files}).
+
+@node Buffer contents, Commands, Getting started, Top
+@comment node-name, next, previous, up
+@chapter Buffer contents
+@cindex Buffer contents
+
+The display contains four columns. They contain, from left to right:
+
+@itemize @bullet
+@item
+An asterisk when the file is @dfn{marked} (@pxref{Selected
+files}).@refill
+@item
+The status of the file. See @xref{File status}, for more information.@refill
+@item
+A "need to be checked in"-marker (@samp{ci}).
+@item
+The file name.
+@end itemize
+
+@menu
+* File status:: The meaning of the second field.
+* Selected files:: How selection works.
+@end menu
+
+@node File status, Selected files, Buffer contents, Buffer contents
+@comment node-name, next, previous, up
+@section File status
+@cindex File status
+@cindex Updated (file status)
+@cindex Modified (file status)
+@cindex Merged (file status)
+@cindex Conflict (file status)
+@cindex Added (file status)
+@cindex Removed (file status)
+@cindex Unknown (file status)
+@cindex Removed from repository (file status)
+@cindex Removed from repository, changed by you (file status)
+@cindex Removed by you, changed in repository (file status)
+@cindex Move away @var{file} - it is in the way (file status)
+@cindex This repository is missing!@dots{} (file status)
+
+The @samp{file status} field can have the following values:
+
+@table @samp
+@item Updated
+The file was brought up to date with respect to the repository. This is
+done for any file that exists in the repository but not in your source,
+and for files that you haven't changed but are not the most recent
+versions available in the repository.@refill
+
+@item Modified
+The file is modified in your working directory, and there was no
+modification to the same file in the repository.@refill
+
+@item Merged
+The file is modified in your working directory, and there were
+modifications in the repository as well as in your copy, but they were
+merged successfully, without conflict, in your working directory.@refill
+
+@item Conflict
+A conflict was detected while trying to merge your changes to @var{file}
+with changes from the source repository. @var{file} (the copy in your
+working directory) is now the output of the @samp{rcsmerge} command on
+the two versions; an unmodified copy of your file is also in your
+working directory, with the name @file{.#@var{file}.@var{version}},
+where @var{version} is the RCS revision that your modified file started
+from. @xref{Viewing differences}, for more details.@refill
+
+@item Added
+The file has been added by you, but it still needs to be checked in to
+the repository.@refill
+
+@item Removed
+The file has been removed by you, but it needs to be checked in to the
+repository. You can resurrect it by typing @kbd{a} (@pxref{Adding and
+removing files}).@refill
+
+@item Unknown
+A file that was detected in your directory, but that neither appears in
+the repository, nor is present on the list of files that CVS should
+ignore.@refill
+
+@end table
+
+There are also a few special cases, that rarely occur, which have longer
+strings in the fields:
+
+@table @samp
+@item Removed from repository
+The file has been removed from your directory since someone has removed
+it from the repository. (It is still present in the Attic directory, so
+no permanent loss has occurred). This, unlike the other entries in this
+table, is not an error condition.@refill
+
+@item Removed from repository, changed by you
+You have modified a file that someone have removed from the repository.
+You can correct this situation by removing the file manually (see
+@pxref{Adding and removing files}).@refill
+
+@item Removed by you, changed in repository
+You have removed a file, and before you committed the removal someone
+committed a change to that file. You could use @kbd{a} to resurrect the
+file (see @pxref{Adding and removing files}).@refill
+
+@item Move away @var{file} - it is in the way
+For some reason CVS does not like the file @var{file}. Rename or remove
+it.@refill
+
+@item This repository is missing! Remove this dir manually.
+It is impossible to remove a directory in the CVS repository in a clean
+way. Someone have tried to remove one, and CVS gets confused. Remove
+your copy of the directory.@refill
+@end table
+
+@node Selected files, , File status, Buffer contents
+@comment node-name, next, previous, up
+@section Selected files
+@cindex Selected files
+@cindex Marked files
+@cindex File selection
+@cindex Active files
+
+Many of the commands works on the current set of @dfn{selected} files.
+
+@itemize @bullet
+@item
+If there are any files that are marked they constitute the set of
+selected files.@refill
+@item
+Otherwise, if the cursor points to a file, that file is the selected
+file.@refill
+@item
+Otherwise, if the cursor points to a directory, all the files in that
+directory that appears in the buffer are the selected files.
+@end itemize
+
+This scheme might seem a little complicated, but once one get used to
+it, it is quite powerful.
+
+@xref{Marking files} tells how you mark and unmark files.
+
+@node Commands, Customization, Buffer contents, Top
+@comment node-name, next, previous, up
+@chapter Commands
+
+@iftex
+This chapter describes all the commands that you can use in pcl-cvs.
+@end iftex
+@ifinfo
+The nodes in this menu contains explanations about all the commands that
+you can use in pcl-cvs. They are grouped together by type.
+@end ifinfo
+
+@menu
+* Updating the directory:: Commands to update the local directory
+* Movement commands:: How to move up and down in the buffer
+* Marking files:: How to mark files that other commands
+ will later operate on.
+* Committing changes:: Checking in your modifications to the
+ CVS repository.
+* Editing files:: Loading files into Emacs.
+* Getting info about files:: Display the log and status of files.
+* Adding and removing files:: Adding and removing files
+* Removing handled entries:: Uninteresting lines can easily be removed.
+* Ignoring files:: Telling CVS to ignore generated files.
+* Viewing differences:: Commands to @samp{diff} different versions.
+@end menu
+
+@node Updating the directory, Movement commands, Commands, Commands
+@comment node-name, next, previous, up
+@section Updating the directory
+@findex cvs-update
+@findex cvs-update-no-prompt
+@kindex g - Rerun @samp{cvs update}
+
+
+@table @kbd
+
+@item M-x cvs-update
+Run a @samp{cvs update} command. You will be asked for the directory in
+which the @samp{cvs update} will be run. The output will be parsed by
+pcl-cvs, and the result printed in the @samp{*cvs*} buffer (see
+@pxref{Buffer contents} for a description of the contents).@refill
+
+By default, @samp{cvs-update} will descend recursively into
+subdirectories. You can avoid that behavior by giving a prefix
+argument to it (e.g., by typing @kbd{C-u M-x cvs-update RET}).@refill
+
+All other commands in pcl-cvs requires that you have a @samp{*cvs*}
+buffer. This is the command that you use to get one.@refill
+
+@item g
+This will run @samp{cvs update} again. It will always use the same
+buffer that was used with the previous @samp{cvs update}. Give a prefix
+argument to avoid descending into subdirectories. This runs the command
+@samp{cvs-update-no-prompt}.@refill
+@end table
+@node Movement commands, Marking files, Updating the directory, Commands
+@comment node-name, next, previous, up
+@section Movement Commands
+@cindex Movement Commands
+@findex cookie-next-cookie
+@findex cookie-previous-cookie
+@kindex SPC - Move down one file
+@kindex C-n - Move down one file
+@kindex n - Move down one file
+@kindex C-p - Move up one file
+@kindex p - Move up on file
+
+You can use most normal Emacs commands to move forward and backward in
+the buffer. Some keys are rebound to functions that take advantage of
+the fact that the buffer is a pcl-cvs buffer:
+
+
+@table @kbd
+@item SPC
+@itemx C-n
+@itemx n
+These keys move the cursor one file forward, towards the end of the
+buffer (@code{cookie-next-cookie}).
+
+@item C-p
+@itemx p
+These keys move one file backward, towards the beginning of the buffer
+(@code{cookie-previous-cookie}).
+@end table
+
+@node Marking files, Committing changes, Movement commands, Commands
+@comment node-name, next, previous, up
+@section Marking files
+@cindex Selecting files (commands to mark files)
+@cindex Marking files
+@kindex m - marking a file
+@kindex M - marking all files
+@kindex u - unmark a file
+@kindex U - unmark all files
+@kindex DEL - unmark previous file
+@findex cvs-mark
+@findex cvs-unmark
+@findex cvs-mark-all-files
+@findex cvs-unmark-all-files
+@findex cvs-unmark-up
+
+Pcl-cvs works on a set of @dfn{selected files} (@pxref{Selected files}).
+You can mark and unmark files with these commands:
+
+@table @kbd
+@item m
+This marks the file that the cursor is positioned on. If the cursor is
+positioned on a directory all files in that directory will be marked.
+(@code{cvs-mark}).
+
+@item u
+Unmark the file that the cursor is positioned on. If the cursor is on a
+directory, all files in that directory will be unmarked.
+(@code{cvs-unmark}).@refill
+
+@item M
+Mark @emph{all} files in the buffer (@code{cvs-mark-all-files}).
+
+@item U
+Unmark @emph{all} files (@code{cvs-unmark-all-files}).
+
+@item @key{DEL}
+Unmark the file on the previous line, and move point to that line
+(@code{cvs-unmark-up}).
+@end table
+
+@node Committing changes, Editing files, Marking files, Commands
+@comment node-name, next, previous, up
+@section Committing changes
+@cindex Committing changes
+@cindex Ci
+@findex cvs-commit
+@kindex c - commit files
+@vindex cvs-erase-input-buffer (variable)
+@cindex Commit buffer
+@cindex Edit buffer
+@cindex Erasing commit message
+
+@table @kbd
+@item c
+All files that have a "need to be checked in"-marker (@pxref{Buffer
+contents}) can be checked in with the @kbd{c} command. It checks in all
+selected files (@pxref{Selected files}) (except those who lack the
+"ci"-marker - they are ignored). Pressing @kbd{c} causes
+@code{cvs-commit} to be run.@refill
+
+When you press @kbd{c} you will get a buffer called
+@samp{*cvs-commit-message*}. Enter the log message for the file(s) in
+it. When you are ready you should press @kbd{C-c C-c} to actually
+commit the files (using @code{cvs-edit-done}).
+
+Normally the @samp{*cvs-commit-message*} buffer will retain the log
+message from the previous commit, but if the variable
+@code{cvs-erase-input-buffer} is set to a non-nil value the buffer will
+be erased. Point and mark will always be located around the entire
+buffer so that you can easily erase it with @kbd{C-w}
+(@samp{kill-region}).@refill
+@end table
+
+@node Editing files, Getting info about files, Committing changes, Commands
+@comment node-name, next, previous, up
+@section Editing files
+
+@cindex Editing files
+@cindex Finding files
+@cindex Loading files
+@cindex Dired
+@cindex Invoking dired
+@findex cvs-find-file
+@findex cvs-find-file-other-window
+@findex cvs-add-change-log-entry-other-window
+@kindex f - find file or directory
+@kindex o - find file in other window
+@kindex A - add ChangeLog entry
+
+There are currently three commands that can be used to find a file (that
+is, load it into a buffer and start editing it there). These commands
+work on the line that the cursor is situated at. They ignore any marked
+files.
+
+@table @kbd
+@item f
+Find the file that the cursor points to. Run @samp{dired}
+@ifinfo
+(@pxref{Dired,,,Emacs})
+@end ifinfo
+if the cursor points to a directory (@code{cvs-find-file}).@refill
+
+@item o
+Like @kbd{f}, but use another window
+(@code{cvs-find-file-other-window}).@refill
+
+@item A
+Invoke @samp{add-change-log-entry-other-window} to edit a
+@samp{ChangeLog} file. The @samp{ChangeLog} will be found in the
+directory of the file the cursor points to.
+(@code{cvs-add-change-log-entry-other-window}).@refill
+@end table
+
+@node Getting info about files, Adding and removing files, Editing files, Commands
+@comment node-name, next, previous, up
+@section Getting info about files
+@cindex Status (cvs command)
+@cindex Log (RCS/cvs command)
+@cindex Getting status
+@kindex l - run @samp{cvs log}
+@kindex s - run @samp{cvs status}
+@findex cvs-log
+@findex cvs-status
+
+Both of the following commands can be customized.
+@xref{Customization}.@refill
+
+@table @kbd
+@item l
+Run @samp{cvs log} on all selected files, and show the result in a
+temporary buffer (@code{cvs-log}).
+
+@item s
+Run @samp{cvs status} on all selected files, and show the result in a
+temporary buffer (@code{cvs-status}).
+@end table
+
+@node Adding and removing files, Removing handled entries, Getting info about files, Commands
+@comment node-name, next, previous, up
+@section Adding and removing files
+@cindex Adding files
+@cindex Removing files
+@cindex Resurrecting files
+@cindex Deleting files
+@cindex Putting files under CVS control
+@kindex a - add a file
+@kindex r - remove a file
+@findex cvs-add
+@findex cvs-remove-file
+
+The following commands are available to make it easy to add and remove
+files from the CVS repository.
+
+@table @kbd
+@item a
+Add all selected files. This command can be used on @samp{Unknown}
+files (see @pxref{File status}). The status of the file will change to
+@samp{Added}, and you will have to use @kbd{c} (@samp{cvs-commit}, see
+@pxref{Committing changes}) to really add the file to the
+repository.@refill
+
+This command can also be used on @samp{Removed} files (before you commit
+them) to resurrect them.
+
+Selected files that are neither @samp{Unknown} nor @samp{Removed} will
+be ignored by this command.
+
+The command that is run is @code{cvs-add}.
+
+@item r
+This command removes the selected files (after prompting for
+confirmation). The files are @samp{rm}ed from your directory and
+(unless the status was @samp{Unknown}; @pxref{File status}) they will
+also be @samp{cvs remove}d. If the files were @samp{Unknown} they will
+disappear from the buffer. Otherwise their status will change to
+@samp{Removed}, and you must use @kbd{c} (@samp{cvs-commit},
+@pxref{Committing changes}) to commit the removal.@refill
+
+The command that is run is @code{cvs-remove-file}.
+@end table
+
+@node Removing handled entries, Ignoring files, Adding and removing files, Commands
+@comment node-name, next, previous, up
+@section Removing handled entries
+@cindex Expunging uninteresting entries
+@cindex Uninteresting entries, getting rid of them
+@cindex Getting rid of uninteresting lines
+@cindex Removing uninteresting (processed) lines
+@cindex Handled lines, removing them
+@kindex x - remove processed entries
+@kindex C-k - remove selected entries
+@findex cvs-remove-handled
+@findex cvs-acknowledge
+
+@table @kbd
+@item x
+This command allows you to remove all entries that you have processed.
+More specifically, the lines for @samp{Updated} files (@pxref{File
+status} and files that have been checked in (@pxref{Committing changes})
+are removed from the buffer. If a directory becomes empty the heading
+for that directory is also removed. This makes it easier to get an
+overview of what needs to be done.
+
+The command is called @code{cvs-remove-handled}. If
+@samp{cvs-auto-remove-handled} is set to non-@samp{nil} this will
+automatically be performed after every commit.@refill
+
+@item C-k
+This command can be used for lines that @samp{cvs-remove-handled} would
+not delete, but that you want to delete (@code{cvs-acknowledge}).
+@end table
+
+@node Ignoring files, Viewing differences, Removing handled entries, Commands
+@comment node-name, next, previous, up
+@section Ignoring files
+
+@table @kbd
+@item i
+Arrange so that CVS will ignore the selected files. The file names are
+added to the @file{.cvsignore} file in the corresponding directory. If
+the @file{.cvsignore} doesn't exist it will be created.
+
+The @file{.cvsignore} file should normally be added to the repository,
+but you could ignore it also if you like it better that way.
+
+This runs @code{cvs-ignore}.
+@end table
+
+@node Viewing differences, , Ignoring files, Commands
+@comment node-name, next, previous, up
+@section Viewing differences
+@cindex Diff
+@cindex Conflicts, how to resolve them
+@cindex Viewing differences
+@kindex d - run @samp{cvs diff}
+@kindex b - diff backup file
+@findex cvs-diff-cvs
+@findex cvs-diff-backup
+
+@table @kbd
+@item d
+Display a @samp{cvs diff} between the selected files and the RCS version
+that they are based on. @xref{Customization} describes how you can send
+flags to @samp{cvs diff}. (The function that does the job is
+@code{cvs-diff-cvs}).@refill
+
+@item b
+If CVS finds a conflict while merging two versions of a file (during a
+@samp{cvs update}, @pxref{Updating the directory}) it will save the
+original file in a file called @file{.#@var{FILE}.@var{VERSION}} where
+@var{FILE} is the name of the file, and @var{VERSION} is the RCS version
+number that your file was based on.
+
+With the @kbd{b} command you can run a @samp{diff} on the files
+@file{.#@var{FILE}.@var{VERSION}} and @file{@var{FILE}}. You can get a
+context- or Unidiff by setting @samp{cvs-diff-flags} -
+@pxref{Customization}. This command only works on files that have
+status @samp{Conflict} or @samp{Merged}. The name of the command is
+@code{cvs-diff-backup}. @refill
+@end table
+
+@node Customization, Future enhancements, Commands, Top
+@comment node-name, next, previous, up
+@chapter Customization
+@vindex cvs-erase-input-buffer (variable)
+@vindex cvs-inhibit-copyright-message (variable)
+@vindex cvs-cvs-diff-flags (variable)
+@vindex cvs-diff-flags (variable)
+@vindex cvs-log-flags (variable)
+@vindex cvs-status-flags (variable)
+@vindex cvs-auto-remove-handled (variable)
+@cindex Inhibiting the Copyright message.
+@cindex Copyright message, getting rid of it
+@cindex Getting rid of the Copyright message.
+@cindex Customization
+@cindex Variables, list of all
+@cindex Erasing the input buffer
+@cindex Context diff, how to get
+@cindex Unidiff, how to get
+@cindex Automatically remove handled files
+
+If you have an idea about any customization that would be handy but
+isn't present in this list, please tell me! @xref{Reporting bugs and
+ideas} for info on how to reach me.@refill
+
+@table @samp
+@item cvs-erase-input-buffer
+If set to anything else than @samp{nil} the edit buffer will be erased
+before you write the log message (@pxref{Committing changes}).
+
+@item cvs-inhibit-copyright-message
+The copyright message that is displayed on startup can be annoying after
+a while. Set this variable to @samp{t} if you want to get rid of it.
+(But don't set this to @samp{t} in the system defaults file - new users
+should see this message at least once).
+
+@item cvs-cvs-diff-flags
+A list of strings to pass as arguments to the @samp{cvs diff} program.
+This is used by @samp{cvs-diff-cvs} (key @kbd{d}, @pxref{Viewing
+differences}). If you prefer the Unidiff format you could add this line
+to your @file{.emacs} file:@refill
+
+@example
+(setq cvs-cvs-diff-flags '("-u"))
+@end example
+
+@item cvs-diff-flags
+Like @samp{cvs-cvs-diff-flags}, but passed to @samp{diff}. This is used
+by @samp{cvs-diff-backup} (key @kbd{b}, @pxref{Viewing differences}).
+
+@item cvs-log-flags
+List of strings to send to @samp{cvs log}. Used by @samp{cvs-log} (key
+@kbd{l}, @pxref{Getting info about files}).
+
+@item cvs-status-flags
+List of strings to send to @samp{cvs status}. Used by @samp{cvs-status}
+(key @kbd{s}, @pxref{Getting info about files}).
+
+@item cvs-auto-remove-handled
+If this variable is set to any non-@samp{nil} value
+@samp{cvs-remove-handled} will be called every time you check in files,
+after the check-in is ready. @xref{Removing handled entries}.@refill
+
+@end table
+@node Future enhancements, Reporting bugs and ideas, Customization, Top
+@comment node-name, next, previous, up
+@chapter Future enhancements
+@cindex Enhancements
+
+Pcl-cvs is still under development and needs a number of enhancements to
+be called complete. Here is my current wish-list for future releases of
+pcl-cvs:
+
+@itemize @bullet
+@item
+Dired support. I have an experimental @file{dired-cvs.el} that works
+together with CVS 1.2. Unfortunately I wrote it on top of a
+non-standard @file{dired.el}, so it must be rewritten.@refill
+
+@item
+It should be possible to run commands such as @samp{cvs log}, @samp{cvs
+status} and @samp{cvs commit} directly from a buffer containing a file,
+instead of having to @samp{cvs-update}. If the directory contains many
+files the @samp{cvs-update} can take quite some time, especially on a
+slow machine.
+@end itemize
+
+
+If you miss something in this wish-list, let me know! I don't promise
+that I will write it, but I will at least try to coordinate the efforts
+of making a good Emacs front end to CVS. See @xref{Reporting bugs and
+ideas} for information about how to reach me.@refill
+
+
+@node Reporting bugs and ideas, Function and Variable Index, Future enhancements, Top
+@comment node-name, next, previous, up
+@chapter Reporting bugs and ideas
+@cindex Reporting bugs and ideas
+@cindex Bugs, how to report them
+@cindex Author, how to reach
+@cindex Email to the author
+
+If you find a bug or misfeature, don't hesitate to tell me! Send email
+to @samp{ceder@@lysator.liu.se}.
+
+If you have ideas for improvements, or if you have written some
+extensions to this package, I would like to hear from you. I hope that
+you find this package useful!
+
+
+@node Function and Variable Index, Concept Index, Reporting bugs and ideas, Top
+@comment node-name, next, previous, up
+@unnumbered Function and Variable Index
+
+@printindex fn
+
+@node Concept Index, Key Index, Function and Variable Index, Top
+@comment node-name, next, previous, up
+@unnumbered Concept Index
+
+@printindex cp
+
+@node Key Index, , Concept Index, Top
+@comment node-name, next, previous, up
+@unnumbered Key Index
+
+@printindex ky
+
+@summarycontents
+@contents
+@bye
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/texinfo.tex b/gnu/usr.bin/cvs/contrib/pcl-cvs/texinfo.tex
new file mode 100644
index 000000000000..05a11d141c29
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/texinfo.tex
@@ -0,0 +1,3230 @@
+%% TeX macros to handle texinfo files
+
+% Copyright (C) 1985, 1986, 1988, 1990, 1991 Free Software Foundation, Inc.
+
+%This texinfo.tex file is free software; you can redistribute it and/or
+%modify it under the terms of the GNU General Public License as
+%published by the Free Software Foundation; either version 2, or (at
+%your option) any later version.
+
+%This texinfo.tex file is distributed in the hope that it will be
+%useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+%of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%General Public License for more details.
+
+%You should have received a copy of the GNU General Public License
+%along with this texinfo.tex file; see the file COPYING. If not, write
+%to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
+%USA.
+
+
+%In other words, you are welcome to use, share and improve this program.
+%You are forbidden to forbid anyone else to use, share and improve
+%what you give them. Help stamp out software-hoarding!
+
+\def\texinfoversion{2.63}
+\message{Loading texinfo package [Version \texinfoversion]:}
+\message{}
+
+% Print the version number if in a .fmt file.
+\everyjob{\message{[Texinfo version \texinfoversion]}\message{}}
+
+% Save some parts of plain tex whose names we will redefine.
+
+\let\ptexlbrace=\{
+\let\ptexrbrace=\}
+\let\ptexdots=\dots
+\let\ptexdot=\.
+\let\ptexstar=\*
+\let\ptexend=\end
+\let\ptexbullet=\bullet
+\let\ptexb=\b
+\let\ptexc=\c
+\let\ptexi=\i
+\let\ptext=\t
+\let\ptexl=\l
+\let\ptexL=\L
+
+\def\tie{\penalty 10000\ } % Save plain tex definition of ~.
+
+\message{Basics,}
+\chardef\other=12
+
+\hyphenation{ap-pen-dix}
+\hyphenation{mini-buf-fer mini-buf-fers}
+\hyphenation{eshell}
+
+% Margin to add to right of even pages, to left of odd pages.
+\newdimen \bindingoffset \bindingoffset=0pt
+\newdimen \normaloffset \normaloffset=\hoffset
+\newdimen\pagewidth \newdimen\pageheight
+\pagewidth=\hsize \pageheight=\vsize
+
+%---------------------Begin change-----------------------
+%
+%%%% For @cropmarks command.
+% Dimensions to add cropmarks at corners Added by P. A. MacKay, 12 Nov. 1986
+%
+\newdimen\cornerlong \newdimen\cornerthick
+\newdimen \topandbottommargin
+\newdimen \outerhsize \newdimen \outervsize
+\cornerlong=1pc\cornerthick=.3pt % These set size of cropmarks
+\outerhsize=7in
+%\outervsize=9.5in
+% Alternative @smallbook page size is 9.25in
+\outervsize=9.25in
+\topandbottommargin=.75in
+%
+%---------------------End change-----------------------
+
+% \onepageout takes a vbox as an argument. Note that \pagecontents
+% does insertions itself, but you have to call it yourself.
+\chardef\PAGE=255 \output={\onepageout{\pagecontents\PAGE}}
+\def\onepageout#1{\hoffset=\normaloffset
+\ifodd\pageno \advance\hoffset by \bindingoffset
+\else \advance\hoffset by -\bindingoffset\fi
+{\escapechar=`\\\relax % makes sure backslash is used in output files.
+\shipout\vbox{{\let\hsize=\pagewidth \makeheadline} \pagebody{#1}%
+{\let\hsize=\pagewidth \makefootline}}}%
+\advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi}
+
+%%%% For @cropmarks command %%%%
+
+% Here is a modification of the main output routine for Near East Publications
+% This provides right-angle cropmarks at all four corners.
+% The contents of the page are centerlined into the cropmarks,
+% and any desired binding offset is added as an \hskip on either
+% site of the centerlined box. (P. A. MacKay, 12 November, 1986)
+%
+\def\croppageout#1{\hoffset=0pt % make sure this doesn't mess things up
+ \shipout
+ \vbox to \outervsize{\hsize=\outerhsize
+ \vbox{\line{\ewtop\hfill\ewtop}}
+ \nointerlineskip
+ \line{\vbox{\moveleft\cornerthick\nstop}
+ \hfill
+ \vbox{\moveright\cornerthick\nstop}}
+ \vskip \topandbottommargin
+ \centerline{\ifodd\pageno\hskip\bindingoffset\fi
+ \vbox{
+ {\let\hsize=\pagewidth \makeheadline}
+ \pagebody{#1}
+ {\let\hsize=\pagewidth \makefootline}}
+ \ifodd\pageno\else\hskip\bindingoffset\fi}
+ \vskip \topandbottommargin plus1fill minus1fill
+ \boxmaxdepth\cornerthick
+ \line{\vbox{\moveleft\cornerthick\nsbot}
+ \hfill
+ \vbox{\moveright\cornerthick\nsbot}}
+ \nointerlineskip
+ \vbox{\line{\ewbot\hfill\ewbot}}
+ }
+ \advancepageno
+ \ifnum\outputpenalty>-20000 \else\dosupereject\fi}
+%
+% Do @cropmarks to get crop marks
+\def\cropmarks{\let\onepageout=\croppageout }
+
+\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}}
+{\catcode`\@ =11
+\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi
+\dimen@=\dp#1 \unvbox#1
+\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi
+\ifr@ggedbottom \kern-\dimen@ \vfil \fi}
+}
+
+%
+% Here are the rules for the cropmarks. Note that they are
+% offset so that the space between them is truly \outerhsize or \outervsize
+% (P. A. MacKay, 12 November, 1986)
+%
+\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong}
+\def\nstop{\vbox
+ {\hrule height\cornerthick depth\cornerlong width\cornerthick}}
+\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong}
+\def\nsbot{\vbox
+ {\hrule height\cornerlong depth\cornerthick width\cornerthick}}
+
+% Parse an argument, then pass it to #1.
+% The argument can be delimited with [...] or with "..." or braces
+% or it can be a whole line.
+% #1 should be a macro which expects
+% an ordinary undelimited TeX argument.
+
+\def\parsearg #1{\let\next=#1\begingroup\obeylines\futurelet\temp\parseargx}
+
+\def\parseargx{%
+\ifx \obeyedspace\temp \aftergroup\parseargdiscardspace \else%
+\aftergroup \parseargline %
+\fi \endgroup}
+
+{\obeyspaces %
+\gdef\parseargdiscardspace {\begingroup\obeylines\futurelet\temp\parseargx}}
+
+\gdef\obeyedspace{\ }
+
+\def\parseargline{\begingroup \obeylines \parsearglinex}
+{\obeylines %
+\gdef\parsearglinex #1^^M{\endgroup \next {#1}}}
+
+\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next}
+
+%% These are used to keep @begin/@end levels from running away
+%% Call \inENV within environments (after a \begingroup)
+\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi}
+\def\ENVcheck{%
+\ifENV\errmessage{Still within an environment. Type Return to continue.}
+\endgroup\fi} % This is not perfect, but it should reduce lossage
+
+% @begin foo is the same as @foo, for now.
+\newhelp\EMsimple{Type <Return> to continue}
+
+\outer\def\begin{\parsearg\beginxxx}
+
+\def\beginxxx #1{%
+\expandafter\ifx\csname #1\endcsname\relax
+{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else
+\csname #1\endcsname\fi}
+
+%% @end foo executes the definition of \Efoo.
+%% foo can be delimited by doublequotes or brackets.
+
+\def\end{\parsearg\endxxx}
+
+\def\endxxx #1{%
+\expandafter\ifx\csname E#1\endcsname\relax
+\expandafter\ifx\csname #1\endcsname\relax
+\errmessage{Undefined command @end #1}\else
+\errorE{#1}\fi\fi
+\csname E#1\endcsname}
+\def\errorE#1{
+{\errhelp=\EMsimple \errmessage{@end #1 not within #1 environment}}}
+
+% Single-spacing is done by various environments.
+
+\newskip\singlespaceskip \singlespaceskip = \baselineskip
+\def\singlespace{%
+{\advance \baselineskip by -\singlespaceskip
+\kern \baselineskip}%
+\baselineskip=\singlespaceskip
+}
+
+%% Simple single-character @ commands
+
+% @@ prints an @
+% Kludge this until the fonts are right (grr).
+\def\@{{\tt \char '100}}
+
+% Define @` and @' to be the same as ` and '
+% but suppressing ligatures.
+\def\`{{`}}
+\def\'{{'}}
+
+% Used to generate quoted braces.
+
+\def\mylbrace {{\tt \char '173}}
+\def\myrbrace {{\tt \char '175}}
+\let\{=\mylbrace
+\let\}=\myrbrace
+
+% @: forces normal size whitespace following.
+\def\:{\spacefactor=1000 }
+
+% @* forces a line break.
+\def\*{\hfil\break\hbox{}\ignorespaces}
+
+% @. is an end-of-sentence period.
+\def\.{.\spacefactor=3000 }
+
+% @w prevents a word break
+\def\w #1{\hbox{#1}}
+
+% @group ... @end group forces ... to be all on one page.
+
+\def\group{\begingroup% \inENV ???
+\ifnum\catcode13=\active \else
+\errmessage{@group invalid in context where filling is enabled}\fi
+\def \Egroup{\egroup\endgroup}
+\vbox\bgroup}
+
+% @need space-in-mils
+% forces a page break if there is not space-in-mils remaining.
+
+\newdimen\mil \mil=0.001in
+
+\def\need{\parsearg\needx}
+
+\def\needx #1{\par %
+% This method tries to make TeX break the page naturally
+% if the depth of the box does not fit.
+{\baselineskip=0pt%
+\vtop to #1\mil{\vfil}\kern -#1\mil\penalty 10000
+\prevdepth=-1000pt
+}}
+
+% @br forces paragraph break
+
+\let\br = \par
+
+% @dots{} output some dots
+
+\def\dots{$\ldots$}
+
+% @page forces the start of a new page
+
+\def\page{\par\vfill\supereject}
+
+% @exdent text....
+% outputs text on separate line in roman font, starting at standard page margin
+
+\def\exdent{\errmessage{@exdent in filled text}}
+ % @lisp, etc, define \exdent locally from \internalexdent
+
+{\obeyspaces
+\gdef\internalexdent{\parsearg\exdentzzz}}
+
+\def\exdentzzz #1{{\advance \leftskip by -\lispnarrowing
+\advance \hsize by -\leftskip
+\advance \hsize by -\rightskip
+\leftline{{\rm#1}}}}
+
+% @include file insert text of that file as input.
+
+\def\include{\parsearg\includezzz}
+\def\includezzz #1{{\def\thisfile{#1}\input #1
+}}
+
+\def\thisfile{}
+
+% @center line outputs that line, centered
+
+\def\center{\parsearg\centerzzz}
+\def\centerzzz #1{{\advance\hsize by -\leftskip
+\advance\hsize by -\rightskip
+\centerline{#1}}}
+
+% @sp n outputs n lines of vertical space
+
+\def\sp{\parsearg\spxxx}
+\def\spxxx #1{\par \vskip #1\baselineskip}
+
+% @comment ...line which is ignored...
+% @c is the same as @comment
+% @ignore ... @end ignore is another way to write a comment
+
+\def\comment{\catcode 64=\other \catcode 123=\other \catcode 125=\other%
+\parsearg \commentxxx}
+
+\def\commentxxx #1{\catcode 64=0 \catcode 123=1 \catcode 125=2 }
+
+\let\c=\comment
+
+% Prevent errors for section commands.
+% Used in @ignore and in failing conditionals.
+\def\ignoresections{%
+\let\chapter=\relax
+\let\unnumbered=\relax
+\let\top=\relax
+\let\unnumberedsec=\relax
+\let\unnumberedsection=\relax
+\let\unnumberedsubsec=\relax
+\let\unnumberedsubsection=\relax
+\let\unnumberedsubsubsec=\relax
+\let\unnumberedsubsubsection=\relax
+\let\section=\relax
+\let\subsec=\relax
+\let\subsubsec=\relax
+\let\subsection=\relax
+\let\subsubsection=\relax
+\let\appendix=\relax
+\let\appendixsec=\relax
+\let\appendixsection=\relax
+\let\appendixsubsec=\relax
+\let\appendixsubsection=\relax
+\let\appendixsubsubsec=\relax
+\let\appendixsubsubsection=\relax
+\let\contents=\relax
+\let\smallbook=\relax
+\let\titlepage=\relax
+}
+
+\def\ignore{\begingroup\ignoresections
+% Make sure that spaces turn into tokens that match what \ignorexxx wants.
+\catcode32=10
+\ignorexxx}
+\long\def\ignorexxx #1\end ignore{\endgroup\ignorespaces}
+
+\def\direntry{\begingroup\direntryxxx}
+\long\def\direntryxxx #1\end direntry{\endgroup\ignorespaces}
+
+% Conditionals to test whether a flag is set.
+
+\def\ifset{\begingroup\ignoresections\parsearg\ifsetxxx}
+
+\def\ifsetxxx #1{\endgroup
+\expandafter\ifx\csname IF#1\endcsname\relax \let\temp=\ifsetfail
+\else \let\temp=\relax \fi
+\temp}
+\def\Eifset{}
+\def\ifsetfail{\begingroup\ignoresections\ifsetfailxxx}
+\long\def\ifsetfailxxx #1\end ifset{\endgroup\ignorespaces}
+
+\def\ifclear{\begingroup\ignoresections\parsearg\ifclearxxx}
+
+\def\ifclearxxx #1{\endgroup
+\expandafter\ifx\csname IF#1\endcsname\relax \let\temp=\relax
+\else \let\temp=\ifclearfail \fi
+\temp}
+\def\Eifclear{}
+\def\ifclearfail{\begingroup\ignoresections\ifclearfailxxx}
+\long\def\ifclearfailxxx #1\end ifclear{\endgroup\ignorespaces}
+
+% @set foo to set the flag named foo.
+% @clear foo to clear the flag named foo.
+\def\set{\parsearg\setxxx}
+\def\setxxx #1{
+\expandafter\let\csname IF#1\endcsname=\set}
+
+\def\clear{\parsearg\clearxxx}
+\def\clearxxx #1{
+\expandafter\let\csname IF#1\endcsname=\relax}
+
+% Some texinfo constructs that are trivial in tex
+
+\def\iftex{}
+\def\Eiftex{}
+\def\ifinfo{\begingroup\ignoresections\ifinfoxxx}
+\long\def\ifinfoxxx #1\end ifinfo{\endgroup\ignorespaces}
+
+\long\def\menu #1\end menu{}
+\def\asis#1{#1}
+
+% @math means output in math mode.
+% We don't use $'s directly in the definition of \math because control
+% sequences like \math are expanded when the toc file is written. Then,
+% we read the toc file back, the $'s will be normal characters (as they
+% should be, according to the definition of Texinfo). So we must use a
+% control sequence to switch into and out of math mode.
+%
+% This isn't quite enough for @math to work properly in indices, but it
+% seems unlikely it will ever be needed there.
+%
+\let\implicitmath = $
+\def\math#1{\implicitmath #1\implicitmath}
+
+\def\node{\ENVcheck\parsearg\nodezzz}
+\def\nodezzz#1{\nodexxx [#1,]}
+\def\nodexxx[#1,#2]{\gdef\lastnode{#1}}
+\let\lastnode=\relax
+
+\def\donoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\setref{\lastnode}\fi
+\let\lastnode=\relax}
+
+\def\unnumbnoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi
+\let\lastnode=\relax}
+
+\def\appendixnoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\appendixsetref{\lastnode}\fi
+\let\lastnode=\relax}
+
+\let\refill=\relax
+
+% @setfilename is done at the beginning of every texinfo file.
+% So open here the files we need to have open while reading the input.
+% This makes it possible to make a .fmt file for texinfo.
+\def\setfilename{%
+ \readauxfile
+ \opencontents
+ \openindices
+ \fixbackslash % Turn off hack to swallow `\input texinfo'.
+ \global\let\setfilename=\comment % Ignore extra @setfilename cmds.
+ \comment % Ignore the actual filename.
+}
+
+\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend}
+
+\def\inforef #1{\inforefzzz #1,,,,**}
+\def\inforefzzz #1,#2,#3,#4**{See Info file \file{\losespace#3{}},
+ node \samp{\losespace#1{}}}
+\def\losespace #1{#1}
+
+\message{fonts,}
+
+% Font-change commands.
+
+% Texinfo supports the sans serif font style, which plain TeX does not.
+% So we set up a \sf analogous to plain's \rm, etc.
+\newfam\sffam
+\def\sf{\fam=\sffam \tensf}
+\let\li = \sf % Sometimes we call it \li, not \sf.
+
+%% Try out Computer Modern fonts at \magstephalf
+\let\mainmagstep=\magstephalf
+
+\ifx\bigger\relax
+\let\mainmagstep=\magstep1
+\font\textrm=cmr12
+\font\texttt=cmtt12
+\else
+\font\textrm=cmr10 scaled \mainmagstep
+\font\texttt=cmtt10 scaled \mainmagstep
+\fi
+% Instead of cmb10, you many want to use cmbx10.
+% cmbx10 is a prettier font on its own, but cmb10
+% looks better when embedded in a line with cmr10.
+\font\textbf=cmb10 scaled \mainmagstep
+\font\textit=cmti10 scaled \mainmagstep
+\font\textsl=cmsl10 scaled \mainmagstep
+\font\textsf=cmss10 scaled \mainmagstep
+\font\textsc=cmcsc10 scaled \mainmagstep
+\font\texti=cmmi10 scaled \mainmagstep
+\font\textsy=cmsy10 scaled \mainmagstep
+
+% A few fonts for @defun, etc.
+\font\defbf=cmbx10 scaled \magstep1 %was 1314
+\font\deftt=cmtt10 scaled \magstep1
+\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf}
+
+% Fonts for indices and small examples.
+% We actually use the slanted font rather than the italic,
+% because texinfo normally uses the slanted fonts for that.
+% Do not make many font distinctions in general in the index, since they
+% aren't very useful.
+\font\ninett=cmtt9
+\font\indrm=cmr9
+\font\indit=cmsl9
+\let\indsl=\indit
+\let\indtt=\ninett
+\let\indsf=\indrm
+\let\indbf=\indrm
+\let\indsc=\indrm
+\font\indi=cmmi9
+\font\indsy=cmsy9
+
+% Fonts for headings
+\font\chaprm=cmbx12 scaled \magstep2
+\font\chapit=cmti12 scaled \magstep2
+\font\chapsl=cmsl12 scaled \magstep2
+\font\chaptt=cmtt12 scaled \magstep2
+\font\chapsf=cmss12 scaled \magstep2
+\let\chapbf=\chaprm
+\font\chapsc=cmcsc10 scaled\magstep3
+\font\chapi=cmmi12 scaled \magstep2
+\font\chapsy=cmsy10 scaled \magstep3
+
+\font\secrm=cmbx12 scaled \magstep1
+\font\secit=cmti12 scaled \magstep1
+\font\secsl=cmsl12 scaled \magstep1
+\font\sectt=cmtt12 scaled \magstep1
+\font\secsf=cmss12 scaled \magstep1
+\font\secbf=cmbx12 scaled \magstep1
+\font\secsc=cmcsc10 scaled\magstep2
+\font\seci=cmmi12 scaled \magstep1
+\font\secsy=cmsy10 scaled \magstep2
+
+% \font\ssecrm=cmbx10 scaled \magstep1 % This size an font looked bad.
+% \font\ssecit=cmti10 scaled \magstep1 % The letters were too crowded.
+% \font\ssecsl=cmsl10 scaled \magstep1
+% \font\ssectt=cmtt10 scaled \magstep1
+% \font\ssecsf=cmss10 scaled \magstep1
+
+%\font\ssecrm=cmb10 scaled 1315 % Note the use of cmb rather than cmbx.
+%\font\ssecit=cmti10 scaled 1315 % Also, the size is a little larger than
+%\font\ssecsl=cmsl10 scaled 1315 % being scaled magstep1.
+%\font\ssectt=cmtt10 scaled 1315
+%\font\ssecsf=cmss10 scaled 1315
+
+%\let\ssecbf=\ssecrm
+
+\font\ssecrm=cmbx12 scaled \magstephalf
+\font\ssecit=cmti12 scaled \magstephalf
+\font\ssecsl=cmsl12 scaled \magstephalf
+\font\ssectt=cmtt12 scaled \magstephalf
+\font\ssecsf=cmss12 scaled \magstephalf
+\font\ssecbf=cmbx12 scaled \magstephalf
+\font\ssecsc=cmcsc10 scaled \magstep1
+\font\sseci=cmmi12 scaled \magstephalf
+\font\ssecsy=cmsy10 scaled \magstep1
+% The smallcaps and symbol fonts should actually be scaled \magstep1.5,
+% but that is not a standard magnification.
+
+% Fonts for title page:
+\font\titlerm = cmbx12 scaled \magstep3
+\let\authorrm = \secrm
+
+% In order for the font changes to affect most math symbols and letters,
+% we have to define the \textfont of the standard families. Since
+% texinfo doesn't allow for producing subscripts and superscripts, we
+% don't bother to reset \scriptfont and \scriptscriptfont (which would
+% also require loading a lot more fonts).
+%
+\def\resetmathfonts{%
+ \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy
+ \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf
+ \textfont\ttfam = \tentt \textfont\sffam = \tensf
+}
+
+
+% The font-changing commands redefine the meanings of \tenSTYLE, instead
+% of just \STYLE. We do this so that font changes will continue to work
+% in math mode, where it is the current \fam that is relevant in most
+% cases, not the current. Plain TeX does, for example,
+% \def\bf{\fam=\bffam \tenbf} By redefining \tenbf, we obviate the need
+% to redefine \bf itself.
+\def\textfonts{%
+ \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl
+ \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc
+ \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy
+ \resetmathfonts}
+\def\chapfonts{%
+ \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl
+ \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc
+ \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy
+ \resetmathfonts}
+\def\secfonts{%
+ \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl
+ \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc
+ \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy
+ \resetmathfonts}
+\def\subsecfonts{%
+ \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl
+ \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc
+ \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy
+ \resetmathfonts}
+\def\indexfonts{%
+ \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl
+ \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc
+ \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy
+ \resetmathfonts}
+
+% Set up the default fonts, so we can use them for creating boxes.
+%
+\textfonts
+
+% Count depth in font-changes, for error checks
+\newcount\fontdepth \fontdepth=0
+
+% Fonts for short table of contents.
+\font\shortcontrm=cmr12
+\font\shortcontbf=cmbx12
+\font\shortcontsl=cmsl12
+
+%% Add scribe-like font environments, plus @l for inline lisp (usually sans
+%% serif) and @ii for TeX italic
+
+% \smartitalic{ARG} outputs arg in italics, followed by an italic correction
+% unless the following character is such as not to need one.
+\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi}
+\def\smartitalic#1{{\sl #1}\futurelet\next\smartitalicx}
+
+\let\i=\smartitalic
+\let\var=\smartitalic
+\let\dfn=\smartitalic
+\let\emph=\smartitalic
+\let\cite=\smartitalic
+
+\def\b#1{{\bf #1}}
+\let\strong=\b
+
+\def\t#1{{\tt \exhyphenpenalty=10000\rawbackslash \frenchspacing #1}\null}
+\let\ttfont = \t
+%\def\samp #1{`{\tt \rawbackslash \frenchspacing #1}'\null}
+\def\samp #1{`\tclose{#1}'\null}
+\def\key #1{{\tt \exhyphenpenalty=10000\uppercase{#1}}\null}
+\def\ctrl #1{{\tt \rawbackslash \hat}#1}
+
+\let\file=\samp
+
+% @code is a modification of @t,
+% which makes spaces the same size as normal in the surrounding text.
+\newdimen\tclosesave
+\newdimen\tcloserm
+\def\tclose#1{{\rm \tcloserm=\fontdimen2\font \tt \tclosesave=\fontdimen2\font
+\fontdimen2\font=\tcloserm
+% prevent breaking lines at hyphens.
+\exhyphenpenalty=10000
+\def\ {{\fontdimen2\font=\tclosesave{} }}%
+ \rawbackslash \frenchspacing #1\fontdimen2\font=\tclosesave}\null}
+\let\code=\tclose
+%\let\exp=\tclose %Was temporary
+
+% @kbd is like @code, except that if the argument is just one @key command,
+% then @kbd has no effect.
+
+\def\xkey{\key}
+\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}%
+\ifx\one\xkey\ifx\threex\three \key{#2}%
+\else\tclose{\look}\fi
+\else\tclose{\look}\fi}
+
+% Typeset a dimension, e.g., `in' or `pt'. The only reason for the
+% argument is to make the input look right: @dmn{pt} instead of
+% @dmn{}pt.
+%
+\def\dmn#1{\thinspace #1}
+
+\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par}
+
+\def\l#1{{\li #1}\null} %
+
+\def\r#1{{\rm #1}} % roman font
+% Use of \lowercase was suggested.
+\def\sc#1{{\smallcaps#1}} % smallcaps font
+\def\ii#1{{\it #1}} % italic font
+
+\message{page headings,}
+
+\newskip\titlepagetopglue \titlepagetopglue = 1.5in
+\newskip\titlepagebottomglue \titlepagebottomglue = 2pc
+
+% First the title page. Must do @settitle before @titlepage.
+\def\titlefont#1{{\titlerm #1}}
+
+\newtoks\realeverypar
+\newif\ifseenauthor
+\newif\iffinishedtitlepage
+
+\def\titlepage{\begingroup \parindent=0pt \textfonts
+ \let\subtitlerm=\tenrm
+% I deinstalled the following change because \cmr12 is undefined.
+% This change was not in the ChangeLog anyway. --rms.
+% \let\subtitlerm=\cmr12
+ \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}%
+ %
+ \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}%
+ %
+ % Leave some space at the very top of the page.
+ \vglue\titlepagetopglue
+ %
+ % Now you can print the title using @title.
+ \def\title{\parsearg\titlezzz}%
+ \def\titlezzz##1{\leftline{\titlefont{##1}}
+ % print a rule at the page bottom also.
+ \finishedtitlepagefalse
+ \vskip4pt \hrule height 4pt \vskip4pt}%
+ % No rule at page bottom unless we print one at the top with @title.
+ \finishedtitlepagetrue
+ %
+ % Now you can put text using @subtitle.
+ \def\subtitle{\parsearg\subtitlezzz}%
+ \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}%
+ %
+ % @author should come last, but may come many times.
+ \def\author{\parsearg\authorzzz}%
+ \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi
+ {\authorfont \leftline{##1}}}%
+ %
+ % Most title ``pages'' are actually two pages long, with space
+ % at the top of the second. We don't want the ragged left on the second.
+ \let\oldpage = \page
+ \def\page{%
+ \iffinishedtitlepage\else
+ \finishtitlepage
+ \fi
+ \oldpage
+ \let\page = \oldpage
+ \hbox{}}%
+% \def\page{\oldpage \hbox{}}
+}
+
+\def\Etitlepage{%
+ \iffinishedtitlepage\else
+ \finishtitlepage
+ \fi
+ % It is important to do the page break before ending the group,
+ % because the headline and footline are only empty inside the group.
+ % If we use the new definition of \page, we always get a blank page
+ % after the title page, which we certainly don't want.
+ \oldpage
+ \endgroup
+ \HEADINGSon
+}
+
+\def\finishtitlepage{%
+ \vskip4pt \hrule height 2pt
+ \vskip\titlepagebottomglue
+ \finishedtitlepagetrue
+}
+
+%%% Set up page headings and footings.
+
+\let\thispage=\folio
+
+\newtoks \evenheadline % Token sequence for heading line of even pages
+\newtoks \oddheadline % Token sequence for heading line of odd pages
+\newtoks \evenfootline % Token sequence for footing line of even pages
+\newtoks \oddfootline % Token sequence for footing line of odd pages
+
+% Now make Tex use those variables
+\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline
+ \else \the\evenheadline \fi}}
+\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline
+ \else \the\evenfootline \fi}\HEADINGShook}
+\let\HEADINGShook=\relax
+
+% Commands to set those variables.
+% For example, this is what @headings on does
+% @evenheading @thistitle|@thispage|@thischapter
+% @oddheading @thischapter|@thispage|@thistitle
+% @evenfooting @thisfile||
+% @oddfooting ||@thisfile
+
+\def\evenheading{\parsearg\evenheadingxxx}
+\def\oddheading{\parsearg\oddheadingxxx}
+\def\everyheading{\parsearg\everyheadingxxx}
+
+\def\evenfooting{\parsearg\evenfootingxxx}
+\def\oddfooting{\parsearg\oddfootingxxx}
+\def\everyfooting{\parsearg\everyfootingxxx}
+
+{\catcode`\@=0 %
+
+\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish}
+\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish}
+\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\everyheadingxxx #1{\everyheadingyyy #1@|@|@|@|\finish}
+\gdef\everyheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish}
+\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish}
+\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\everyfootingxxx #1{\everyfootingyyy #1@|@|@|@|\finish}
+\gdef\everyfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}
+\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+%
+}% unbind the catcode of @.
+
+% @headings double turns headings on for double-sided printing.
+% @headings single turns headings on for single-sided printing.
+% @headings off turns them off.
+% @headings on same as @headings double, retained for compatibility.
+% @headings after turns on double-sided headings after this page.
+% @headings doubleafter turns on double-sided headings after this page.
+% @headings singleafter turns on single-sided headings after this page.
+% By default, they are off.
+
+\def\headings #1 {\csname HEADINGS#1\endcsname}
+
+\def\HEADINGSoff{
+\global\evenheadline={\hfil} \global\evenfootline={\hfil}
+\global\oddheadline={\hfil} \global\oddfootline={\hfil}}
+\HEADINGSoff
+% When we turn headings on, set the page number to 1.
+% For double-sided printing, put current file name in lower left corner,
+% chapter name on inside top of right hand pages, document
+% title on inside top of left hand pages, and page numbers on outside top
+% edge of all pages.
+\def\HEADINGSdouble{
+%\pagealignmacro
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+% For single-sided printing, chapter title goes across top left of page,
+% page number on top right.
+\def\HEADINGSsingle{
+%\pagealignmacro
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+\def\HEADINGSon{\HEADINGSdouble}
+
+\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex}
+\let\HEADINGSdoubleafter=\HEADINGSafter
+\def\HEADINGSdoublex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+
+\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex}
+\def\HEADINGSsinglex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+
+% Subroutines used in generating headings
+% Produces Day Month Year style of output.
+\def\today{\number\day\space
+\ifcase\month\or
+January\or February\or March\or April\or May\or June\or
+July\or August\or September\or October\or November\or December\fi
+\space\number\year}
+
+% Use this if you want the Month Day, Year style of output.
+%\def\today{\ifcase\month\or
+%January\or February\or March\or April\or May\or June\or
+%July\or August\or September\or October\or November\or December\fi
+%\space\number\day, \number\year}
+
+% @settitle line... specifies the title of the document, for headings
+% It generates no output of its own
+
+\def\thistitle{No Title}
+\def\settitle{\parsearg\settitlezzz}
+\def\settitlezzz #1{\gdef\thistitle{#1}}
+
+\message{tables,}
+
+% @tabs -- simple alignment
+
+% These don't work. For one thing, \+ is defined as outer.
+% So these macros cannot even be defined.
+
+%\def\tabs{\parsearg\tabszzz}
+%\def\tabszzz #1{\settabs\+#1\cr}
+%\def\tabline{\parsearg\tablinezzz}
+%\def\tablinezzz #1{\+#1\cr}
+%\def\&{&}
+
+% Tables -- @table, @ftable, @item(x), @kitem(x), @xitem(x).
+
+% default indentation of table text
+\newdimen\tableindent \tableindent=.8in
+% default indentation of @itemize and @enumerate text
+\newdimen\itemindent \itemindent=.3in
+% margin between end of table item and start of table text.
+\newdimen\itemmargin \itemmargin=.1in
+
+% used internally for \itemindent minus \itemmargin
+\newdimen\itemmax
+
+% Note @table and @ftable define @item, @itemx, etc., with these defs.
+% They also define \itemindex
+% to index the item name in whatever manner is desired (perhaps none).
+
+\def\internalBitem{\smallbreak \parsearg\itemzzz}
+\def\internalBitemx{\par \parsearg\itemzzz}
+
+\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz}
+\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \par \parsearg\xitemzzz}
+
+\def\internalBkitem{\smallbreak \parsearg\kitemzzz}
+\def\internalBkitemx{\par \parsearg\kitemzzz}
+
+\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}%
+ \itemzzz {#1}}
+
+\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}%
+ \itemzzz {#1}}
+
+\def\itemzzz #1{\begingroup %
+ \advance\hsize by -\rightskip
+ \advance\hsize by -\tableindent
+ \setbox0=\hbox{\itemfont{#1}}%
+ \itemindex{#1}%
+ \nobreak % This prevents a break before @itemx.
+ %
+ % Be sure we are not still in the middle of a paragraph.
+ \parskip=0in
+ \par
+ %
+ % If the item text does not fit in the space we have, put it on a line
+ % by itself, and do not allow a page break either before or after that
+ % line. We do not start a paragraph here because then if the next
+ % command is, e.g., @kindex, the whatsit would get put into the
+ % horizontal list on a line by itself, resulting in extra blank space.
+ \ifdim \wd0>\itemmax
+ \setbox0=\hbox{\hskip \leftskip \hskip -\tableindent \unhbox0}\box0
+ \nobreak
+ \else
+ % The item text fits into the space. Start a paragraph, so that the
+ % following text (if any) will end up on the same line. Since that
+ % text will be indented by \tableindent, we make the item text be in
+ % a zero-width box.
+ \noindent
+ \rlap{\hskip -\tableindent\box0}%
+ \fi
+ \endgroup
+}
+
+\def\item{\errmessage{@item while not in a table}}
+\def\itemx{\errmessage{@itemx while not in a table}}
+\def\kitem{\errmessage{@kitem while not in a table}}
+\def\kitemx{\errmessage{@kitemx while not in a table}}
+\def\xitem{\errmessage{@xitem while not in a table}}
+\def\xitemx{\errmessage{@xitemx while not in a table}}
+
+%% Contains a kludge to get @end[description] to work
+\def\description{\tablez{\dontindex}{1}{}{}{}{}}
+
+\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex}
+{\obeylines\obeyspaces%
+\gdef\tablex #1^^M{%
+\tabley\dontindex#1 \endtabley}}
+
+\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex}
+{\obeylines\obeyspaces%
+\gdef\ftablex #1^^M{%
+\tabley\fnitemindex#1 \endtabley
+\def\Eftable{\endgraf\endgroup\afterenvbreak}%
+\let\Etable=\relax}}
+
+\def\dontindex #1{}
+\def\fnitemindex #1{\doind {fn}{\code{#1}}}%
+
+{\obeyspaces %
+\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup%
+\tablez{#1}{#2}{#3}{#4}{#5}{#6}}}
+
+\def\tablez #1#2#3#4#5#6{%
+\aboveenvbreak %
+\begingroup %
+\def\Edescription{\Etable}% Neccessary kludge.
+\let\itemindex=#1%
+\ifnum 0#3>0 \advance \leftskip by #3\mil \fi %
+\ifnum 0#4>0 \tableindent=#4\mil \fi %
+\ifnum 0#5>0 \advance \rightskip by #5\mil \fi %
+\def\itemfont{#2}%
+\itemmax=\tableindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \tableindent %
+\parindent = 0pt
+\parskip = \smallskipamount
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def\Etable{\endgraf\endgroup\afterenvbreak}%
+\let\item = \internalBitem %
+\let\itemx = \internalBitemx %
+\let\kitem = \internalBkitem %
+\let\kitemx = \internalBkitemx %
+\let\xitem = \internalBxitem %
+\let\xitemx = \internalBxitemx %
+}
+
+% This is the counter used by @enumerate, which is really @itemize
+
+\newcount \itemno
+
+\def\itemize{\parsearg\itemizezzz}
+
+\def\itemizezzz #1{%
+ \begingroup % ended by the @end itemsize
+ \itemizey {#1}{\Eitemize}
+}
+
+\def\itemizey #1#2{%
+\aboveenvbreak %
+\itemmax=\itemindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \itemindent %
+\parindent = 0pt %
+\parskip = \smallskipamount %
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def#2{\endgraf\endgroup\afterenvbreak}%
+\def\itemcontents{#1}%
+\let\item=\itemizeitem}
+
+\def\bullet{$\ptexbullet$}
+\def\minus{$-$}
+
+% Set sfcode to normal for the chars that usually have another value.
+% These are `.?!:;,'
+\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000
+ \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 }
+
+% \splitoff TOKENS\endmark defines \first to be the first token in
+% TOKENS, and \rest to be the remainder.
+%
+\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}%
+
+% Allow an optional argument of an uppercase letter, lowercase letter,
+% or number, to specify the first label in the enumerated list. No
+% argument is the same as `1'.
+%
+\def\enumerate{\parsearg\enumeratezzz}
+\def\enumeratezzz #1{\enumeratey #1 \endenumeratey}
+\def\enumeratey #1 #2\endenumeratey{%
+ \begingroup % ended by the @end enumerate
+ %
+ % If we were given no argument, pretend we were given `1'.
+ \def\thearg{#1}%
+ \ifx\thearg\empty \def\thearg{1}\fi
+ %
+ % Detect if the argument is a single token. If so, it might be a
+ % letter. Otherwise, the only valid thing it can be is a number.
+ % (We will always have one token, because of the test we just made.
+ % This is a good thing, since \splitoff doesn't work given nothing at
+ % all -- the first parameter is undelimited.)
+ \expandafter\splitoff\thearg\endmark
+ \ifx\rest\empty
+ % Only one token in the argument. It could still be anything.
+ % A ``lowercase letter'' is one whose \lccode is nonzero.
+ % An ``uppercase letter'' is one whose \lccode is both nonzero, and
+ % not equal to itself.
+ % Otherwise, we assume it's a number.
+ %
+ % We need the \relax at the end of the \ifnum lines to stop TeX from
+ % continuing to look for a <number>.
+ %
+ \ifnum\lccode\expandafter`\thearg=0\relax
+ \numericenumerate % a number (we hope)
+ \else
+ % It's a letter.
+ \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax
+ \lowercaseenumerate % lowercase letter
+ \else
+ \uppercaseenumerate % uppercase letter
+ \fi
+ \fi
+ \else
+ % Multiple tokens in the argument. We hope it's a number.
+ \numericenumerate
+ \fi
+}
+
+% An @enumerate whose labels are integers. The starting integer is
+% given in \thearg.
+%
+\def\numericenumerate{%
+ \itemno = \thearg
+ \startenumeration{\the\itemno}%
+}
+
+% The starting (lowercase) letter is in \thearg.
+\def\lowercaseenumerate{%
+ \itemno = \expandafter`\thearg
+ \startenumeration{%
+ % Be sure we're not beyond the end of the alphabet.
+ \ifnum\itemno=0
+ \errmessage{No more lowercase letters in @enumerate; get a bigger
+ alphabet}%
+ \fi
+ \char\lccode\itemno
+ }%
+}
+
+% The starting (uppercase) letter is in \thearg.
+\def\uppercaseenumerate{%
+ \itemno = \expandafter`\thearg
+ \startenumeration{%
+ % Be sure we're not beyond the end of the alphabet.
+ \ifnum\itemno=0
+ \errmessage{No more uppercase letters in @enumerate; get a bigger
+ alphabet}
+ \fi
+ \char\uccode\itemno
+ }%
+}
+
+% Call itemizey, adding a period to the first argument and supplying the
+% common last two arguments. Also subtract one from the initial value in
+% \itemno, since @item increments \itemno.
+%
+\def\startenumeration#1{%
+ \advance\itemno by -1
+ \itemizey{#1.}\Eenumerate\flushcr
+}
+
+% @alphaenumerate and @capsenumerate are abbreviations for giving an arg
+% to @enumerate.
+%
+\def\alphaenumerate{\enumerate{a}}
+\def\capsenumerate{\enumerate{A}}
+\def\Ealphaenumerate{\Eenumerate}
+\def\Ecapsenumerate{\Eenumerate}
+
+% Definition of @item while inside @itemize.
+
+\def\itemizeitem{%
+\advance\itemno by 1
+{\let\par=\endgraf \smallbreak}%
+\ifhmode \errmessage{\in hmode at itemizeitem}\fi
+{\parskip=0in \hskip 0pt
+\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}%
+\vadjust{\penalty 1200}}%
+\flushcr}
+
+\message{indexing,}
+% Index generation facilities
+
+% Define \newwrite to be identical to plain tex's \newwrite
+% except not \outer, so it can be used within \newindex.
+{\catcode`\@=11
+\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}}
+
+% \newindex {foo} defines an index named foo.
+% It automatically defines \fooindex such that
+% \fooindex ...rest of line... puts an entry in the index foo.
+% It also defines \fooindfile to be the number of the output channel for
+% the file that accumulates this index. The file's extension is foo.
+% The name of an index should be no more than 2 characters long
+% for the sake of vms.
+
+\def\newindex #1{
+\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file
+\openout \csname#1indfile\endcsname \jobname.#1 % Open the file
+\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex
+\noexpand\doindex {#1}}
+}
+
+% @defindex foo == \newindex{foo}
+
+\def\defindex{\parsearg\newindex}
+
+% Define @defcodeindex, like @defindex except put all entries in @code.
+
+\def\newcodeindex #1{
+\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file
+\openout \csname#1indfile\endcsname \jobname.#1 % Open the file
+\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex
+\noexpand\docodeindex {#1}}
+}
+
+\def\defcodeindex{\parsearg\newcodeindex}
+
+% @synindex foo bar makes index foo feed into index bar.
+% Do this instead of @defindex foo if you don't want it as a separate index.
+\def\synindex #1 #2 {%
+\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname
+\expandafter\let\csname#1indfile\endcsname=\synindexfoo
+\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex
+\noexpand\doindex {#2}}%
+}
+
+% @syncodeindex foo bar similar, but put all entries made for index foo
+% inside @code.
+\def\syncodeindex #1 #2 {%
+\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname
+\expandafter\let\csname#1indfile\endcsname=\synindexfoo
+\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex
+\noexpand\docodeindex {#2}}%
+}
+
+% Define \doindex, the driver for all \fooindex macros.
+% Argument #1 is generated by the calling \fooindex macro,
+% and it is "foo", the name of the index.
+
+% \doindex just uses \parsearg; it calls \doind for the actual work.
+% This is because \doind is more useful to call from other macros.
+
+% There is also \dosubind {index}{topic}{subtopic}
+% which makes an entry in a two-level index such as the operation index.
+
+\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer}
+\def\singleindexer #1{\doind{\indexname}{#1}}
+
+% like the previous two, but they put @code around the argument.
+\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer}
+\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}}
+
+\def\indexdummies{%
+\def\_{{\realbackslash _}}%
+\def\w{\realbackslash w }%
+\def\bf{\realbackslash bf }%
+\def\rm{\realbackslash rm }%
+\def\sl{\realbackslash sl }%
+\def\sf{\realbackslash sf}%
+\def\tt{\realbackslash tt}%
+\def\gtr{\realbackslash gtr}%
+\def\less{\realbackslash less}%
+\def\hat{\realbackslash hat}%
+\def\char{\realbackslash char}%
+\def\TeX{\realbackslash TeX}%
+\def\dots{\realbackslash dots }%
+\def\copyright{\realbackslash copyright }%
+\def\tclose##1{\realbackslash tclose {##1}}%
+\def\code##1{\realbackslash code {##1}}%
+\def\samp##1{\realbackslash samp {##1}}%
+\def\t##1{\realbackslash r {##1}}%
+\def\r##1{\realbackslash r {##1}}%
+\def\i##1{\realbackslash i {##1}}%
+\def\b##1{\realbackslash b {##1}}%
+\def\cite##1{\realbackslash cite {##1}}%
+\def\key##1{\realbackslash key {##1}}%
+\def\file##1{\realbackslash file {##1}}%
+\def\var##1{\realbackslash var {##1}}%
+\def\kbd##1{\realbackslash kbd {##1}}%
+}
+
+% \indexnofonts no-ops all font-change commands.
+% This is used when outputting the strings to sort the index by.
+\def\indexdummyfont#1{#1}
+\def\indexdummytex{TeX}
+\def\indexdummydots{...}
+
+\def\indexnofonts{%
+\let\w=\indexdummyfont
+\let\t=\indexdummyfont
+\let\r=\indexdummyfont
+\let\i=\indexdummyfont
+\let\b=\indexdummyfont
+\let\emph=\indexdummyfont
+\let\strong=\indexdummyfont
+\let\cite=\indexdummyfont
+\let\sc=\indexdummyfont
+%Don't no-op \tt, since it isn't a user-level command
+% and is used in the definitions of the active chars like <, >, |...
+%\let\tt=\indexdummyfont
+\let\tclose=\indexdummyfont
+\let\code=\indexdummyfont
+\let\file=\indexdummyfont
+\let\samp=\indexdummyfont
+\let\kbd=\indexdummyfont
+\let\key=\indexdummyfont
+\let\var=\indexdummyfont
+\let\TeX=\indexdummytex
+\let\dots=\indexdummydots
+}
+
+% To define \realbackslash, we must make \ not be an escape.
+% We must first make another character (@) an escape
+% so we do not become unable to do a definition.
+
+{\catcode`\@=0 \catcode`\\=\other
+@gdef@realbackslash{\}}
+
+\let\indexbackslash=0 %overridden during \printindex.
+
+\def\doind #1#2{%
+{\count10=\lastpenalty %
+{\indexdummies % Must do this here, since \bf, etc expand at this stage
+\escapechar=`\\%
+{\let\folio=0% Expand all macros now EXCEPT \folio
+\def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now
+% so it will be output as is; and it will print as backslash in the indx.
+%
+% Now process the index-string once, with all font commands turned off,
+% to get the string to sort the index by.
+{\indexnofonts
+\xdef\temp1{#2}%
+}%
+% Now produce the complete index entry. We process the index-string again,
+% this time with font commands expanded, to get what to print in the index.
+\edef\temp{%
+\write \csname#1indfile\endcsname{%
+\realbackslash entry {\temp1}{\folio}{#2}}}%
+\temp }%
+}\penalty\count10}}
+
+\def\dosubind #1#2#3{%
+{\count10=\lastpenalty %
+{\indexdummies % Must do this here, since \bf, etc expand at this stage
+\escapechar=`\\%
+{\let\folio=0%
+\def\rawbackslashxx{\indexbackslash}%
+%
+% Now process the index-string once, with all font commands turned off,
+% to get the string to sort the index by.
+{\indexnofonts
+\xdef\temp1{#2 #3}%
+}%
+% Now produce the complete index entry. We process the index-string again,
+% this time with font commands expanded, to get what to print in the index.
+\edef\temp{%
+\write \csname#1indfile\endcsname{%
+\realbackslash entry {\temp1}{\folio}{#2}{#3}}}%
+\temp }%
+}\penalty\count10}}
+
+% The index entry written in the file actually looks like
+% \entry {sortstring}{page}{topic}
+% or
+% \entry {sortstring}{page}{topic}{subtopic}
+% The texindex program reads in these files and writes files
+% containing these kinds of lines:
+% \initial {c}
+% before the first topic whose initial is c
+% \entry {topic}{pagelist}
+% for a topic that is used without subtopics
+% \primary {topic}
+% for the beginning of a topic that is used with subtopics
+% \secondary {subtopic}{pagelist}
+% for each subtopic.
+
+% Define the user-accessible indexing commands
+% @findex, @vindex, @kindex, @cindex.
+
+\def\findex {\fnindex}
+\def\kindex {\kyindex}
+\def\cindex {\cpindex}
+\def\vindex {\vrindex}
+\def\tindex {\tpindex}
+\def\pindex {\pgindex}
+
+\def\cindexsub {\begingroup\obeylines\cindexsub}
+{\obeylines %
+\gdef\cindexsub "#1" #2^^M{\endgroup %
+\dosubind{cp}{#2}{#1}}}
+
+% Define the macros used in formatting output of the sorted index material.
+
+% This is what you call to cause a particular index to get printed.
+% Write
+% @unnumbered Function Index
+% @printindex fn
+
+\def\printindex{\parsearg\doprintindex}
+
+\def\doprintindex#1{%
+ \tex
+ \dobreak \chapheadingskip {10000}
+ \catcode`\%=\other\catcode`\&=\other\catcode`\#=\other
+ \catcode`\$=\other\catcode`\_=\other
+ \catcode`\~=\other
+ %
+ % The following don't help, since the chars were translated
+ % when the raw index was written, and their fonts were discarded
+ % due to \indexnofonts.
+ %\catcode`\"=\active
+ %\catcode`\^=\active
+ %\catcode`\_=\active
+ %\catcode`\|=\active
+ %\catcode`\<=\active
+ %\catcode`\>=\active
+ % %
+ \def\indexbackslash{\rawbackslashxx}
+ \indexfonts\rm \tolerance=9500 \advance\baselineskip -1pt
+ \begindoublecolumns
+ %
+ % See if the index file exists and is nonempty.
+ \openin 1 \jobname.#1s
+ \ifeof 1
+ % \enddoublecolumns gets confused if there is no text in the index,
+ % and it loses the chapter title and the aux file entries for the
+ % index. The easiest way to prevent this problem is to make sure
+ % there is some text.
+ (Index is nonexistent)
+ \else
+ %
+ % If the index file exists but is empty, then \openin leaves \ifeof
+ % false. We have to make TeX try to read something from the file, so
+ % it can discover if there is anything in it.
+ \read 1 to \temp
+ \ifeof 1
+ (Index is empty)
+ \else
+ \input \jobname.#1s
+ \fi
+ \fi
+ \closein 1
+ \enddoublecolumns
+ \Etex
+}
+
+% These macros are used by the sorted index file itself.
+% Change them to control the appearance of the index.
+
+% Same as \bigskipamount except no shrink.
+% \balancecolumns gets confused if there is any shrink.
+\newskip\initialskipamount \initialskipamount 12pt plus4pt
+
+\def\initial #1{%
+{\let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt
+\ifdim\lastskip<\initialskipamount
+\removelastskip \penalty-200 \vskip \initialskipamount\fi
+\line{\secbf#1\hfill}\kern 2pt\penalty10000}}
+
+\def\entry #1#2{
+{\parfillskip=0in \parskip=0in \parindent=0in
+\hangindent=1in \hangafter=1%
+\noindent\hbox{#1}\indexdotfill #2\par
+}}
+
+% Like \dotfill except takes at least 1 em.
+\def\indexdotfill{\cleaders
+ \hbox{$\mathsurround=0pt \mkern1.5mu . \mkern1.5mu$}\hskip 1em plus 1fill}
+
+\def\primary #1{\line{#1\hfil}}
+
+\newskip\secondaryindent \secondaryindent=0.5cm
+
+\def\secondary #1#2{
+{\parfillskip=0in \parskip=0in
+\hangindent =1in \hangafter=1
+\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par
+}}
+
+%% Define two-column mode, which is used in indexes.
+%% Adapted from the TeXBook, page 416
+\catcode `\@=11
+
+\newbox\partialpage
+
+\newdimen\doublecolumnhsize \doublecolumnhsize = 3.11in
+\newdimen\doublecolumnvsize \doublecolumnvsize = 19.1in
+\newdimen\availdimen@
+
+\def\begindoublecolumns{\begingroup
+ \output={\global\setbox\partialpage=
+ \vbox{\unvbox255\kern -\topskip \kern \baselineskip}}\eject
+ \output={\doublecolumnout}%
+ \hsize=\doublecolumnhsize \vsize=\doublecolumnvsize}
+\def\enddoublecolumns{\output={\balancecolumns}\eject
+ \endgroup \pagegoal=\vsize}
+
+\def\doublecolumnout{\splittopskip=\topskip \splitmaxdepth=\maxdepth
+ \dimen@=\pageheight \advance\dimen@ by-\ht\partialpage
+ \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@
+ \onepageout\pagesofar \unvbox255 \penalty\outputpenalty}
+\def\pagesofar{\unvbox\partialpage %
+ \hsize=\doublecolumnhsize % have to restore this since output routine
+% changes it to set cropmarks (P. A. MacKay, 12 Nov. 1986)
+ \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}}
+\def\balancecolumns{%
+% Unset the glue.
+ \setbox255=\vbox{\unvbox255}
+ \dimen@=\ht255
+ \advance\dimen@ by\topskip \advance\dimen@ by-\baselineskip
+ \divide\dimen@ by2
+ \availdimen@=\pageheight \advance\availdimen@ by-\ht\partialpage
+% If the remaining data is too big for one page,
+% output one page normally, then work with what remains.
+ \ifdim \dimen@>\availdimen@
+ {
+ \splittopskip=\topskip \splitmaxdepth=\maxdepth
+ \dimen@=\pageheight \advance\dimen@ by-\ht\partialpage
+ \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@
+ \onepageout\pagesofar
+ }
+% Recompute size of what remains, in case we just output some of it.
+ \dimen@=\ht255
+ \advance\dimen@ by\topskip \advance\dimen@ by-\baselineskip
+ \divide\dimen@ by2
+ \fi
+ \setbox0=\vbox{\unvbox255}
+ \splittopskip=\topskip
+ {\vbadness=10000 \loop \global\setbox3=\copy0
+ \global\setbox1=\vsplit3 to\dimen@
+ \ifdim\ht3>\dimen@ \global\advance\dimen@ by1pt \repeat}
+ \setbox0=\vbox to\dimen@{\unvbox1} \setbox2=\vbox to\dimen@{\unvbox3}
+ \pagesofar}
+
+\catcode `\@=\other
+\message{sectioning,}
+% Define chapters, sections, etc.
+
+\newcount \chapno
+\newcount \secno \secno=0
+\newcount \subsecno \subsecno=0
+\newcount \subsubsecno \subsubsecno=0
+
+% This counter is funny since it counts through charcodes of letters A, B, ...
+\newcount \appendixno \appendixno = `\@
+\def\appendixletter{\char\the\appendixno}
+
+\newwrite \contentsfile
+% This is called from \setfilename.
+\def\opencontents{\openout \contentsfile = \jobname.toc}
+
+% Each @chapter defines this as the name of the chapter.
+% page headings and footings can use it. @section does likewise
+
+\def\thischapter{} \def\thissection{}
+\def\seccheck#1{\if \pageno<0 %
+\errmessage{@#1 not allowed after generating table of contents}\fi
+%
+}
+
+\def\chapternofonts{%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\def\TeX{\realbackslash TeX}
+\def\dots{\realbackslash dots}
+\def\copyright{\realbackslash copyright}
+\def\tt{\realbackslash tt}
+\def\bf{\realbackslash bf }
+\def\w{\realbackslash w}
+\def\less{\realbackslash less}
+\def\gtr{\realbackslash gtr}
+\def\hat{\realbackslash hat}
+\def\char{\realbackslash char}
+\def\tclose##1{\realbackslash tclose {##1}}
+\def\code##1{\realbackslash code {##1}}
+\def\samp##1{\realbackslash samp {##1}}
+\def\r##1{\realbackslash r {##1}}
+\def\b##1{\realbackslash b {##1}}
+\def\key##1{\realbackslash key {##1}}
+\def\file##1{\realbackslash file {##1}}
+\def\kbd##1{\realbackslash kbd {##1}}
+% These are redefined because @smartitalic wouldn't work inside xdef.
+\def\i##1{\realbackslash i {##1}}
+\def\cite##1{\realbackslash cite {##1}}
+\def\var##1{\realbackslash var {##1}}
+\def\emph##1{\realbackslash emph {##1}}
+\def\dfn##1{\realbackslash dfn {##1}}
+}
+
+\def\thischaptername{No Chapter Title}
+\outer\def\chapter{\parsearg\chapterzzz}
+\def\chapterzzz #1{\seccheck{chapter}%
+\secno=0 \subsecno=0 \subsubsecno=0
+\global\advance \chapno by 1 \message{Chapter \the\chapno}%
+\chapmacro {#1}{\the\chapno}%
+\gdef\thissection{#1}%
+\gdef\thischaptername{#1}%
+% We don't substitute the actual chapter name into \thischapter
+% because we don't want its macros evaluated now.
+\xdef\thischapter{Chapter \the\chapno: \noexpand\thischaptername}%
+{\chapternofonts%
+\edef\temp{{\realbackslash chapentry {#1}{\the\chapno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\global\let\section = \numberedsec
+\global\let\subsection = \numberedsubsec
+\global\let\subsubsection = \numberedsubsubsec
+}}
+
+\outer\def\appendix{\parsearg\appendixzzz}
+\def\appendixzzz #1{\seccheck{appendix}%
+\secno=0 \subsecno=0 \subsubsecno=0
+\global\advance \appendixno by 1 \message{Appendix \appendixletter}%
+\chapmacro {#1}{Appendix \appendixletter}%
+\gdef\thissection{#1}%
+\gdef\thischaptername{#1}%
+\xdef\thischapter{Appendix \appendixletter: \noexpand\thischaptername}%
+{\chapternofonts%
+\edef\temp{{\realbackslash chapentry
+ {#1}{Appendix \appendixletter}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\appendixnoderef %
+\global\let\section = \appendixsec
+\global\let\subsection = \appendixsubsec
+\global\let\subsubsection = \appendixsubsubsec
+}}
+
+\outer\def\top{\parsearg\unnumberedzzz}
+\outer\def\unnumbered{\parsearg\unnumberedzzz}
+\def\unnumberedzzz #1{\seccheck{unnumbered}%
+\secno=0 \subsecno=0 \subsubsecno=0 \message{(#1)}
+\unnumbchapmacro {#1}%
+\gdef\thischapter{#1}\gdef\thissection{#1}%
+{\chapternofonts%
+\edef\temp{{\realbackslash unnumbchapentry {#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\global\let\section = \unnumberedsec
+\global\let\subsection = \unnumberedsubsec
+\global\let\subsubsection = \unnumberedsubsubsec
+}}
+
+\outer\def\numberedsec{\parsearg\seczzz}
+\def\seczzz #1{\seccheck{section}%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash secentry %
+{#1}{\the\chapno}{\the\secno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}}
+
+\outer\def\appendixsection{\parsearg\appendixsectionzzz}
+\outer\def\appendixsec{\parsearg\appendixsectionzzz}
+\def\appendixsectionzzz #1{\seccheck{appendixsection}%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash secentry %
+{#1}{\appendixletter}{\the\secno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\appendixnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\unnumberedsec{\parsearg\unnumberedseczzz}
+\def\unnumberedseczzz #1{\seccheck{unnumberedsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+{\chapternofonts%
+\edef\temp{{\realbackslash unnumbsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\numberedsubsec{\parsearg\numberedsubseczzz}
+\def\numberedsubseczzz #1{\seccheck{subsection}%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash subsecentry %
+{#1}{\the\chapno}{\the\secno}{\the\subsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}}
+
+\outer\def\appendixsubsec{\parsearg\appendixsubseczzz}
+\def\appendixsubseczzz #1{\seccheck{appendixsubsec}%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash subsecentry %
+{#1}{\appendixletter}{\the\secno}{\the\subsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\appendixnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\unnumberedsubsec{\parsearg\unnumberedsubseczzz}
+\def\unnumberedsubseczzz #1{\seccheck{unnumberedsubsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+{\chapternofonts%
+\edef\temp{{\realbackslash unnumbsubsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\numberedsubsubsec{\parsearg\numberedsubsubseczzz}
+\def\numberedsubsubseczzz #1{\seccheck{subsubsection}%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}
+ {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash subsubsecentry %
+ {#1}
+ {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}
+ {\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}}
+
+\outer\def\appendixsubsubsec{\parsearg\appendixsubsubseczzz}
+\def\appendixsubsubseczzz #1{\seccheck{appendixsubsubsec}%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}
+ {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash subsubsecentry{#1}%
+ {\appendixletter}
+ {\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\appendixnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz}
+\def\unnumberedsubsubseczzz #1{\seccheck{unnumberedsubsubsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+{\chapternofonts%
+\edef\temp{{\realbackslash unnumbsubsubsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}}
+
+% These are variants which are not "outer", so they can appear in @ifinfo.
+% Actually, they should now be obsolete; ordinary section commands should work.
+\def\infotop{\parsearg\unnumberedzzz}
+\def\infounnumbered{\parsearg\unnumberedzzz}
+\def\infounnumberedsec{\parsearg\unnumberedseczzz}
+\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz}
+\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz}
+
+\def\infoappendix{\parsearg\appendixzzz}
+\def\infoappendixsec{\parsearg\appendixseczzz}
+\def\infoappendixsubsec{\parsearg\appendixsubseczzz}
+\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz}
+
+\def\infochapter{\parsearg\chapterzzz}
+\def\infosection{\parsearg\sectionzzz}
+\def\infosubsection{\parsearg\subsectionzzz}
+\def\infosubsubsection{\parsearg\subsubsectionzzz}
+
+% These macros control what the section commands do, according
+% to what kind of chapter we are in (ordinary, appendix, or unnumbered).
+% Define them by default for a numbered chapter.
+\global\let\section = \numberedsec
+\global\let\subsection = \numberedsubsec
+\global\let\subsubsection = \numberedsubsubsec
+
+% Define @majorheading, @heading and @subheading
+
+% NOTE on use of \vbox for chapter headings, section headings, and
+% such:
+% 1) We use \vbox rather than the earlier \line to permit
+% overlong headings to fold.
+% 2) \hyphenpenalty is set to 10000 because hyphenation in a
+% heading is obnoxious; this forbids it.
+% 3) Likewise, headings look best if no \parindent is used, and
+% if justification is not attempted. Hence \raggedright.
+
+
+\def\majorheading{\parsearg\majorheadingzzz}
+\def\majorheadingzzz #1{%
+{\advance\chapheadingskip by 10pt \chapbreak }%
+{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}\bigskip \par\penalty 200}
+
+\def\chapheading{\parsearg\chapheadingzzz}
+\def\chapheadingzzz #1{\chapbreak %
+{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}\bigskip \par\penalty 200}
+
+\def\heading{\parsearg\secheadingi}
+
+\def\subheading{\parsearg\subsecheadingi}
+
+\def\subsubheading{\parsearg\subsubsecheadingi}
+
+% These macros generate a chapter, section, etc. heading only
+% (including whitespace, linebreaking, etc. around it),
+% given all the information in convenient, parsed form.
+
+%%% Args are the skip and penalty (usually negative)
+\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi}
+
+\def\setchapterstyle #1 {\csname CHAPF#1\endcsname}
+
+%%% Define plain chapter starts, and page on/off switching for it
+% Parameter controlling skip before chapter headings (if needed)
+
+\newskip \chapheadingskip \chapheadingskip = 30pt plus 8pt minus 4pt
+
+\def\chapbreak{\dobreak \chapheadingskip {-4000}}
+\def\chappager{\par\vfill\supereject}
+\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi}
+
+\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname}
+
+\def\CHAPPAGoff{
+\global\let\pchapsepmacro=\chapbreak
+\global\let\pagealignmacro=\chappager}
+
+\def\CHAPPAGon{
+\global\let\pchapsepmacro=\chappager
+\global\let\pagealignmacro=\chappager
+\global\def\HEADINGSon{\HEADINGSsingle}}
+
+\def\CHAPPAGodd{
+\global\let\pchapsepmacro=\chapoddpage
+\global\let\pagealignmacro=\chapoddpage
+\global\def\HEADINGSon{\HEADINGSdouble}}
+
+\CHAPPAGon
+
+\def\CHAPFplain{
+\global\let\chapmacro=\chfplain
+\global\let\unnumbchapmacro=\unnchfplain}
+
+\def\chfplain #1#2{%
+ \pchapsepmacro
+ {%
+ \chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #2\enspace #1}%
+ }%
+ \bigskip
+ \penalty5000
+}
+
+\def\unnchfplain #1{%
+\pchapsepmacro %
+{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}\bigskip \par\penalty 10000 %
+}
+\CHAPFplain % The default
+
+\def\unnchfopen #1{%
+\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}\bigskip \par\penalty 10000 %
+}
+
+\def\chfopen #1#2{\chapoddpage {\chapfonts
+\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}%
+\par\penalty 5000 %
+}
+
+\def\CHAPFopen{
+\global\let\chapmacro=\chfopen
+\global\let\unnumbchapmacro=\unnchfopen}
+
+% Parameter controlling skip before section headings.
+
+\newskip \subsecheadingskip \subsecheadingskip = 17pt plus 8pt minus 4pt
+\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}}
+
+\newskip \secheadingskip \secheadingskip = 21pt plus 8pt minus 4pt
+\def\secheadingbreak{\dobreak \secheadingskip {-1000}}
+
+% @paragraphindent is defined for the Info formatting commands only.
+\let\paragraphindent=\comment
+
+% Section fonts are the base font at magstep2, which produces
+% a size a bit more than 14 points in the default situation.
+
+\def\secheading #1#2#3{\secheadingi {#2.#3\enspace #1}}
+\def\plainsecheading #1{\secheadingi {#1}}
+\def\secheadingi #1{{\advance \secheadingskip by \parskip %
+\secheadingbreak}%
+{\secfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 }
+
+
+% Subsection fonts are the base font at magstep1,
+% which produces a size of 12 points.
+
+\def\subsecheading #1#2#3#4{\subsecheadingi {#2.#3.#4\enspace #1}}
+\def\subsecheadingi #1{{\advance \subsecheadingskip by \parskip %
+\subsecheadingbreak}%
+{\subsecfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 }
+
+\def\subsubsecfonts{\subsecfonts} % Maybe this should change:
+ % Perhaps make sssec fonts scaled
+ % magstep half
+\def\subsubsecheading #1#2#3#4#5{\subsubsecheadingi {#2.#3.#4.#5\enspace #1}}
+\def\subsubsecheadingi #1{{\advance \subsecheadingskip by \parskip %
+\subsecheadingbreak}%
+{\subsubsecfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000}
+
+
+\message{toc printing,}
+
+% Finish up the main text and prepare to read what we've written
+% to \contentsfile.
+
+\newskip\contentsrightmargin \contentsrightmargin=1in
+\def\startcontents#1{%
+ \ifnum \pageno>0
+ \pagealignmacro
+ \immediate\closeout \contentsfile
+ \pageno = -1 % Request roman numbered pages.
+ \fi
+ % Don't need to put `Contents' or `Short Contents' in the headline.
+ % It is abundantly clear what they are.
+ \unnumbchapmacro{#1}\def\thischapter{}%
+ \begingroup % Set up to handle contents files properly.
+ \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11
+ \raggedbottom % Worry more about breakpoints than the bottom.
+ \advance\hsize by -\contentsrightmargin % Don't use the full line length.
+}
+
+
+% Normal (long) toc.
+\outer\def\contents{%
+ \startcontents{Table of Contents}%
+ \input \jobname.toc
+ \endgroup
+ \vfill \eject
+}
+
+% And just the chapters.
+\outer\def\summarycontents{%
+ \startcontents{Short Contents}%
+ %
+ \let\chapentry = \shortchapentry
+ \let\unnumbchapentry = \shortunnumberedentry
+ % We want a true roman here for the page numbers.
+ \secfonts
+ \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl
+ \rm
+ \advance\baselineskip by 1pt % Open it up a little.
+ \def\secentry ##1##2##3##4{}
+ \def\unnumbsecentry ##1##2{}
+ \def\subsecentry ##1##2##3##4##5{}
+ \def\unnumbsubsecentry ##1##2{}
+ \def\subsubsecentry ##1##2##3##4##5##6{}
+ \def\unnumbsubsubsecentry ##1##2{}
+ \input \jobname.toc
+ \endgroup
+ \vfill \eject
+}
+\let\shortcontents = \summarycontents
+
+% These macros generate individual entries in the table of contents.
+% The first argument is the chapter or section name.
+% The last argument is the page number.
+% The arguments in between are the chapter number, section number, ...
+
+% Chapter-level things, for both the long and short contents.
+\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}}
+
+% See comments in \dochapentry re vbox and related settings
+\def\shortchapentry#1#2#3{%
+ \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\strut\raggedright
+ {#2\labelspace #1}\dotfill\doshortpageno{#3}}%
+}
+
+\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}}
+\def\shortunnumberedentry#1#2{%
+ \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\strut\raggedright
+ #1\dotfill\doshortpageno{#2}}%
+}
+
+% Sections.
+\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}}
+\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}}
+
+% Subsections.
+\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}}
+\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}}
+
+% And subsubsections.
+\def\subsubsecentry#1#2#3#4#5#6{%
+ \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}}
+\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}}
+
+
+% This parameter controls the indentation of the various levels.
+\newdimen\tocindent \tocindent = 3pc
+
+% Now for the actual typesetting. In all these, #1 is the text and #2 is the
+% page number.
+%
+% If the toc has to be broken over pages, we would want to be at chapters
+% if at all possible; hence the \penalty.
+\def\dochapentry#1#2{%
+ \penalty-300 \vskip\baselineskip
+ % This \vbox (and similar ones in dosecentry etc.) used to be a
+ % \line; changed to permit linebreaks for long headings. See
+ % comments above \majorheading. Here we also use \strut to
+ % keep the top end of the vbox from jamming up against the previous
+ % entry in the table of contents.
+ \vbox{\chapentryfonts
+ \hyphenpenalty=10000\tolerance=5000 % this line and next introduced
+ \parindent=0pt\strut\raggedright % with \line -> \vbox change
+ #1\dotfill
+ \dopageno{#2}}%
+ \nobreak\vskip .25\baselineskip
+}
+
+\def\dosecentry#1#2{%
+ \vbox{\secentryfonts \leftskip=\tocindent
+ \hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\strut\raggedright #1\dotfill
+ \dopageno{#2}}%
+}
+
+\def\dosubsecentry#1#2{%
+ \vbox{\subsecentryfonts \leftskip=2\tocindent
+ \hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\strut\raggedright #1\dotfill
+ \dopageno{#2}}%
+}
+
+\def\dosubsubsecentry#1#2{%
+ \vbox{\subsubsecentryfonts \leftskip=3\tocindent
+ \hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\strut\raggedright #1\dotfill
+ \dopageno{#2}}%
+}
+
+% Space between chapter (or whatever) number and the title.
+\def\labelspace{\hskip1em \relax}
+
+\def\dopageno#1{{\rm #1}}
+\def\doshortpageno#1{{\rm #1}}
+
+\def\chapentryfonts{\secfonts \rm}
+\def\secentryfonts{\textfonts}
+\let\subsecentryfonts = \textfonts
+\let\subsubsecentryfonts = \textfonts
+
+
+\message{environments,}
+
+% Since these characters are used in examples, it should be an even number of
+% \tt widths. Each \tt character is 1en, so two makes it 1em.
+% Furthermore, these definitions must come after we define our fonts.
+\newbox\dblarrowbox \newbox\longdblarrowbox
+\newbox\pushcharbox \newbox\bullbox
+\newbox\equivbox \newbox\errorbox
+
+\let\ptexequiv = \equiv
+
+{\tentt
+\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil}
+\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil}
+\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil}
+\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil}
+% Adapted from the manmac format (p.420 of TeXbook)
+\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex
+ depth .1ex\hfil}
+}
+
+\def\point{$\star$}
+
+\def\result{\leavevmode\raise.15ex\copy\dblarrowbox}
+\def\expansion{\leavevmode\raise.1ex\copy\longdblarrowbox}
+\def\print{\leavevmode\lower.1ex\copy\pushcharbox}
+
+\def\equiv{\leavevmode\lower.1ex\copy\equivbox}
+
+% Does anyone really want this?
+% \def\bull{\leavevmode\copy\bullbox}
+
+% Adapted from the TeXbook's \boxit.
+{\tentt \global\dimen0 = 3em}% Width of the box.
+\dimen2 = .55pt % Thickness of rules
+% The text. (`r' is open on the right, `e' somewhat less so on the left.)
+\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt}
+
+\global\setbox\errorbox=\hbox to \dimen0{\hfil
+ \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right.
+ \advance\hsize by -2\dimen2 % Rules.
+ \vbox{
+ \hrule height\dimen2
+ \hbox{\vrule width\dimen2 \kern3pt % Space to left of text.
+ \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below.
+ \kern3pt\vrule width\dimen2}% Space to right.
+ \hrule height\dimen2}
+ \hfil}
+
+% The @error{} command.
+\def\error{\leavevmode\lower.7ex\copy\errorbox}
+
+% @tex ... @end tex escapes into raw Tex temporarily.
+% One exception: @ is still an escape character, so that @end tex works.
+% But \@ or @@ will get a plain tex @ character.
+
+\def\tex{\begingroup
+\catcode `\\=0 \catcode `\{=1 \catcode `\}=2
+\catcode `\$=3 \catcode `\&=4 \catcode `\#=6
+\catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie
+\catcode `\%=14
+\catcode 43=12
+\catcode`\"=12
+\catcode`\==12
+\catcode`\|=12
+\catcode`\<=12
+\catcode`\>=12
+\escapechar=`\\
+%
+\let\{=\ptexlbrace
+\let\}=\ptexrbrace
+\let\.=\ptexdot
+\let\*=\ptexstar
+\let\dots=\ptexdots
+\def\@{@}%
+\let\bullet=\ptexbullet
+\let\b=\ptexb \let\c=\ptexc \let\i=\ptexi \let\t=\ptext \let\l=\ptexl
+\let\L=\ptexL
+%
+\let\Etex=\endgroup}
+
+% Define @lisp ... @endlisp.
+% @lisp does a \begingroup so it can rebind things,
+% including the definition of @endlisp (which normally is erroneous).
+
+% Amount to narrow the margins by for @lisp.
+\newskip\lispnarrowing \lispnarrowing=0.4in
+
+% This is the definition that ^M gets inside @lisp
+% phr: changed space to \null, to avoid overfull hbox problems.
+{\obeyspaces%
+\gdef\lisppar{\null\endgraf}}
+
+% Cause \obeyspaces to make each Space cause a word-separation
+% rather than the default which is that it acts punctuation.
+% This is because space in tt font looks funny.
+{\obeyspaces %
+\gdef\sepspaces{\def {\ }}}
+
+\newskip\aboveenvskipamount \aboveenvskipamount= 0pt
+\def\aboveenvbreak{{\advance\aboveenvskipamount by \parskip
+\endgraf \ifdim\lastskip<\aboveenvskipamount
+\removelastskip \penalty-50 \vskip\aboveenvskipamount \fi}}
+
+\def\afterenvbreak{\endgraf \ifdim\lastskip<\aboveenvskipamount
+\removelastskip \penalty-50 \vskip\aboveenvskipamount \fi}
+
+% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins.
+\let\nonarrowing=\relax
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \cartouche: draw rectangle w/rounded corners around argument
+\font\circle=lcircle10
+\newdimen\circthick
+\newdimen\cartouter\newdimen\cartinner
+\newskip\normbskip\newskip\normpskip\newskip\normlskip
+\circthick=\fontdimen8\circle
+%
+\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth
+\def\ctr{{\hskip 6pt\circle\char'010}}
+\def\cbl{{\circle\char'012\hskip -6pt}}
+\def\cbr{{\hskip 6pt\circle\char'011}}
+\def\carttop{\hbox to \cartouter{\hskip\lskip
+ \ctl\leaders\hrule height\circthick\hfil\ctr
+ \hskip\rskip}}
+\def\cartbot{\hbox to \cartouter{\hskip\lskip
+ \cbl\leaders\hrule height\circthick\hfil\cbr
+ \hskip\rskip}}
+%
+\newskip\lskip\newskip\rskip
+
+\long\def\cartouche{%
+\begingroup
+ \lskip=\leftskip \rskip=\rightskip
+ \leftskip=0pt\rightskip=0pt %we want these *outside*.
+ \cartinner=\hsize \advance\cartinner by-\lskip
+ \advance\cartinner by-\rskip
+ \cartouter=\hsize
+ \advance\cartouter by 18pt % allow for 3pt kerns on either
+% side, and for 6pt waste from
+% each corner char
+ \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip
+ % Flag to tell @lisp, etc., not to narrow margin.
+ \let\nonarrowing=\comment
+ \vbox\bgroup
+ \baselineskip=0pt\parskip=0pt\lineskip=0pt
+ \carttop
+ \hbox\bgroup
+ \hskip\lskip
+ \vrule\kern3pt
+ \vbox\bgroup
+ \hsize=\cartinner
+ \kern3pt
+ \begingroup
+ \baselineskip=\normbskip
+ \lineskip=\normlskip
+ \parskip=\normpskip
+ \vskip -\parskip
+\def\Ecartouche{%
+ \endgroup
+ \kern3pt
+ \egroup
+ \kern3pt\vrule
+ \hskip\rskip
+ \egroup
+ \cartbot
+ \egroup
+\endgroup
+}}
+
+\def\lisp{\aboveenvbreak
+\begingroup\inENV % This group ends at the end of the @lisp body
+\hfuzz=12truept % Don't be fussy
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% Single space lines
+\singlespace %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+\let\par=\lisppar
+\def\Elisp{\endgroup\afterenvbreak}%
+\parskip=0pt
+% @cartouche defines \nonarrowing to inhibit narrowing
+% at next level down.
+\ifx\nonarrowing\relax
+\advance \leftskip by \lispnarrowing
+\let\nonarrowing=\relax
+\fi
+\parindent=0pt
+\let\exdent=\internalexdent
+\obeyspaces \obeylines \tt \rawbackslash
+\def\next##1{}\next}
+
+
+\let\example=\lisp
+\def\Eexample{\Elisp}
+
+\let\smallexample=\lisp
+\def\Esmallexample{\Elisp}
+
+% Macro for 9 pt. examples, necessary to print with 5" lines.
+% From Pavel@xerox. This is not really used unless the
+% @smallbook command is given.
+
+\def\smalllispx{\aboveenvbreak\begingroup\inENV
+% This group ends at the end of the @lisp body
+\hfuzz=12truept % Don't be fussy
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% Single space lines
+\singlespace %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+\let\par=\lisppar
+\def\Esmalllisp{\endgroup\afterenvbreak}%
+\parskip=0pt
+% @cartouche defines \nonarrowing to inhibit narrowing
+% at next level down.
+\ifx\nonarrowing\relax
+\advance \leftskip by \lispnarrowing
+\let\nonarrowing=\relax
+\fi
+\parindent=0pt
+\let\exdent=\internalexdent
+\obeyspaces \obeylines \ninett \indexfonts \rawbackslash
+\def\next##1{}\next}
+
+% This is @display; same as @lisp except use roman font.
+
+\def\display{\begingroup\inENV %This group ends at the end of the @display body
+\aboveenvbreak
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% Single space lines
+\singlespace %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+\let\par=\lisppar
+\def\Edisplay{\endgroup\afterenvbreak}%
+\parskip=0pt
+% @cartouche defines \nonarrowing to inhibit narrowing
+% at next level down.
+\ifx\nonarrowing\relax
+\advance \leftskip by \lispnarrowing
+\let\nonarrowing=\relax
+\fi
+\parindent=0pt
+\let\exdent=\internalexdent
+\obeyspaces \obeylines
+\def\next##1{}\next}
+
+% This is @format; same as @lisp except use roman font and don't narrow margins
+
+\def\format{\begingroup\inENV %This group ends at the end of the @format body
+\aboveenvbreak
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+\singlespace %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+\let\par=\lisppar
+\def\Eformat{\endgroup\afterenvbreak}
+\parskip=0pt \parindent=0pt
+\obeyspaces \obeylines
+\def\next##1{}\next}
+
+% @flushleft and @flushright
+
+\def\flushleft{%
+\begingroup\inENV %This group ends at the end of the @format body
+\aboveenvbreak
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+% This also causes @ to work when the directive name
+% is terminated by end of line.
+\let\par=\lisppar
+\def\Eflushleft{\endgroup\afterenvbreak}%
+\parskip=0pt \parindent=0pt
+\obeyspaces \obeylines
+\def\next##1{}\next}
+
+\def\flushright{%
+\begingroup\inENV %This group ends at the end of the @format body
+\aboveenvbreak
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+% This also causes @ to work when the directive name
+% is terminated by end of line.
+\let\par=\lisppar
+\def\Eflushright{\endgroup\afterenvbreak}%
+\parskip=0pt \parindent=0pt
+\advance \leftskip by 0pt plus 1fill
+\obeyspaces \obeylines
+\def\next##1{}\next}
+
+% @quotation - narrow the margins.
+
+\def\quotation{%
+\begingroup\inENV %This group ends at the end of the @quotation body
+{\parskip=0pt % because we will skip by \parskip too, later
+\aboveenvbreak}%
+\singlespace
+\parindent=0pt
+\def\Equotation{\par\endgroup\afterenvbreak}%
+% @cartouche defines \nonarrowing to inhibit narrowing
+% at next level down.
+\ifx\nonarrowing\relax
+\advance \leftskip by \lispnarrowing
+\advance \rightskip by \lispnarrowing
+\let\nonarrowing=\relax
+\fi}
+
+\message{defuns,}
+% Define formatter for defuns
+% First, allow user to change definition object font (\df) internally
+\def\setdeffont #1 {\csname DEF#1\endcsname}
+
+\newskip\defbodyindent \defbodyindent=.4in
+\newskip\defargsindent \defargsindent=50pt
+\newskip\deftypemargin \deftypemargin=12pt
+\newskip\deflastargmargin \deflastargmargin=18pt
+
+\newcount\parencount
+% define \functionparens, which makes ( and ) and & do special things.
+% \functionparens affects the group it is contained in.
+\def\activeparens{%
+\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active
+\catcode`\[=\active \catcode`\]=\active}
+{\activeparens % Now, smart parens don't turn on until &foo (see \amprm)
+\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 }
+\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
+
+% Definitions of (, ) and & used in args for functions.
+% This is the definition of ( outside of all parentheses.
+\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested %
+\global\advance\parencount by 1 }
+%
+% This is the definition of ( when already inside a level of parens.
+\gdef\opnested{\char`\(\global\advance\parencount by 1 }
+%
+\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0.
+% also in that case restore the outer-level definition of (.
+\ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi
+\global\advance \parencount by -1 }
+% If we encounter &foo, then turn on ()-hacking afterwards
+\gdef\amprm#1 {{\rm\&#1}\let(=\oprm \let)=\clrm\ }
+%
+\gdef\normalparens{\boldbrax\let&=\ampnr}
+} % End of definition inside \activeparens
+%% These parens (in \boldbrax) actually are a little bolder than the
+%% contained text. This is especially needed for [ and ]
+\def\opnr{{\sf\char`\(}} \def\clnr{{\sf\char`\)}} \def\ampnr{\&}
+\def\lbrb{{\bf\char`\[}} \def\rbrb{{\bf\char`\]}}
+
+% First, defname, which formats the header line itself.
+% #1 should be the function name.
+% #2 should be the type of definition, such as "Function".
+
+\def\defname #1#2{%
+% Get the values of \leftskip and \rightskip as they were
+% outside the @def...
+\dimen2=\leftskip
+\advance\dimen2 by -\defbodyindent
+\dimen3=\rightskip
+\advance\dimen3 by -\defbodyindent
+\noindent %
+\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}%
+\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line
+\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations
+\parshape 2 0in \dimen0 \defargsindent \dimen1 %
+% Now output arg 2 ("Function" or some such)
+% ending at \deftypemargin from the right margin,
+% but stuck inside a box of width 0 so it does not interfere with linebreaking
+{% Adjust \hsize to exclude the ambient margins,
+% so that \rightline will obey them.
+\advance \hsize by -\dimen2 \advance \hsize by -\dimen3
+\rlap{\rightline{{\rm #2}\hskip \deftypemargin}}}%
+% Make all lines underfull and no complaints:
+\tolerance=10000 \hbadness=10000
+\advance\leftskip by -\defbodyindent
+{\df #1}\enskip % Generate function name
+}
+
+% Actually process the body of a definition
+% #1 should be the terminating control sequence, such as \Edefun.
+% #2 should be the "another name" control sequence, such as \defunx.
+% #3 should be the control sequence that actually processes the header,
+% such as \defunheader.
+
+\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2{\begingroup\obeylines\activeparens\spacesplit#3}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\begingroup %
+\catcode 61=\active %
+\obeylines\activeparens\spacesplit#3}
+
+\def\defmethparsebody #1#2#3#4 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#4}}}
+
+\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\def#4{##1}%
+\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#5}}}
+
+% These parsing functions are similar to the preceding ones
+% except that they do not make parens into active characters.
+% These are used for "variables" since they have no arguments.
+
+\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2{\begingroup\obeylines\spacesplit#3}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\begingroup %
+\catcode 61=\active %
+\obeylines\spacesplit#3}
+
+\def\defvrparsebody #1#2#3#4 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\begingroup\obeylines\spacesplit{#3{#4}}}
+
+\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\def#4{##1}%
+\begingroup\obeylines\spacesplit{#3{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\begingroup\obeylines\spacesplit{#3{#5}}}
+
+% Split up #2 at the first space token.
+% call #1 with two arguments:
+% the first is all of #2 before the space token,
+% the second is all of #2 after that space token.
+% If #2 contains no space token, all of it is passed as the first arg
+% and the second is passed as empty.
+
+{\obeylines
+\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}%
+\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{%
+\ifx\relax #3%
+#1{#2}{}\else #1{#2}{#3#4}\fi}}
+
+% So much for the things common to all kinds of definitions.
+
+% Define @defun.
+
+% First, define the processing that is wanted for arguments of \defun
+% Use this to expand the args and terminate the paragraph they make up
+
+\def\defunargs #1{\functionparens \sl
+% Expand, preventing hyphenation at `-' chars.
+% Note that groups don't affect changes in \hyphenchar.
+\hyphenchar\tensl=0
+#1%
+\hyphenchar\tensl=45
+\ifnum\parencount=0 \else \errmessage{unbalanced parens in @def arguments}\fi%
+\interlinepenalty=10000
+\advance\rightskip by 0pt plus 1fil
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000%
+}
+
+\def\deftypefunargs #1{%
+% Expand, preventing hyphenation at `-' chars.
+% Note that groups don't affect changes in \hyphenchar.
+\functionparens
+\code{#1}%
+\interlinepenalty=10000
+\advance\rightskip by 0pt plus 1fil
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000%
+}
+
+% Do complete processing of one @defun or @defunx line already parsed.
+
+% @deffn Command forward-char nchars
+
+\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader}
+
+\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defun == @deffn Function
+
+\def\defun{\defparsebody\Edefun\defunx\defunheader}
+
+\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Function}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @deftypefun int foobar (int @var{foo}, float @var{bar})
+
+\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader}
+
+% #1 is the data type. #2 is the name and args.
+\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax}
+% #1 is the data type, #2 the name, #3 the args.
+\def\deftypefunheaderx #1#2 #3\relax{%
+\doind {fn}{\code{#2}}% Make entry in function index
+\begingroup\defname {\code{#1} #2}{Function}%
+\deftypefunargs {#3}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar})
+
+\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader}
+
+% #1 is the classification. #2 is the data type. #3 is the name and args.
+\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax}
+% #1 is the classification, #2 the data type, #3 the name, #4 the args.
+\def\deftypefnheaderx #1#2#3 #4\relax{%
+\doind {fn}{\code{#3}}% Make entry in function index
+\begingroup\defname {\code{#2} #3}{#1}%
+\deftypefunargs {#4}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defmac == @deffn Macro
+
+\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader}
+
+\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Macro}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defspec == @deffn Special Form
+
+\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader}
+
+\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Special Form}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% This definition is run if you use @defunx
+% anywhere other than immediately after a @defun or @defunx.
+
+\def\deffnx #1 {\errmessage{@deffnx in invalid context}}
+\def\defunx #1 {\errmessage{@defunx in invalid context}}
+\def\defmacx #1 {\errmessage{@defmacx in invalid context}}
+\def\defspecx #1 {\errmessage{@defspecx in invalid context}}
+\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}}
+\def\deftypeunx #1 {\errmessage{@deftypeunx in invalid context}}
+
+% @defmethod, and so on
+
+% @defop {Funny Method} foo-class frobnicate argument
+
+\def\defop #1 {\def\defoptype{#1}%
+\defopparsebody\Edefop\defopx\defopheader\defoptype}
+
+\def\defopheader #1#2#3{%
+\dosubind {fn}{\code{#2}}{on #1}% Make entry in function index
+\begingroup\defname {#2}{\defoptype{} on #1}%
+\defunargs {#3}\endgroup %
+}
+
+% @defmethod == @defop Method
+
+\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader}
+
+\def\defmethodheader #1#2#3{%
+\dosubind {fn}{\code{#2}}{on #1}% entry in function index
+\begingroup\defname {#2}{Method on #1}%
+\defunargs {#3}\endgroup %
+}
+
+% @defcv {Class Option} foo-class foo-flag
+
+\def\defcv #1 {\def\defcvtype{#1}%
+\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype}
+
+\def\defcvarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index
+\begingroup\defname {#2}{\defcvtype{} of #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% @defivar == @defcv {Instance Variable}
+
+\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader}
+
+\def\defivarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index
+\begingroup\defname {#2}{Instance Variable of #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% These definitions are run if you use @defmethodx, etc.,
+% anywhere other than immediately after a @defmethod, etc.
+
+\def\defopx #1 {\errmessage{@defopx in invalid context}}
+\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}}
+\def\defcvx #1 {\errmessage{@defcvx in invalid context}}
+\def\defivarx #1 {\errmessage{@defivarx in invalid context}}
+
+% Now @defvar
+
+% First, define the processing that is wanted for arguments of @defvar.
+% This is actually simple: just print them in roman.
+% This must expand the args and terminate the paragraph they make up
+\def\defvarargs #1{\normalparens #1%
+\interlinepenalty=10000
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000}
+
+% @defvr Counter foo-count
+
+\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader}
+
+\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup}
+
+% @defvar == @defvr Variable
+
+\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader}
+
+\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{Variable}%
+\defvarargs {#2}\endgroup %
+}
+
+% @defopt == @defvr {User Option}
+
+\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader}
+
+\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{User Option}%
+\defvarargs {#2}\endgroup %
+}
+
+% @deftypevar int foobar
+
+\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader}
+
+% #1 is the data type. #2 is the name.
+\def\deftypevarheader #1#2{%
+\doind {vr}{\code{#2}}% Make entry in variables index
+\begingroup\defname {\code{#1} #2}{Variable}%
+\interlinepenalty=10000
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000
+\endgroup}
+
+% @deftypevr {Global Flag} int enable
+
+\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader}
+
+\def\deftypevrheader #1#2#3{\doind {vr}{\code{#3}}%
+\begingroup\defname {\code{#2} #3}{#1}
+\interlinepenalty=10000
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000
+\endgroup}
+
+% This definition is run if you use @defvarx
+% anywhere other than immediately after a @defvar or @defvarx.
+
+\def\defvrx #1 {\errmessage{@defvrx in invalid context}}
+\def\defvarx #1 {\errmessage{@defvarx in invalid context}}
+\def\defoptx #1 {\errmessage{@defoptx in invalid context}}
+\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}}
+\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}}
+
+% Now define @deftp
+% Args are printed in bold, a slight difference from @defvar.
+
+\def\deftpargs #1{\bf \defvarargs{#1}}
+
+% @deftp Class window height width ...
+
+\def\deftp{\defvrparsebody\Edeftp\deftpx\deftpheader}
+
+\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}%
+\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup}
+
+% This definition is run if you use @deftpx, etc
+% anywhere other than immediately after a @deftp, etc.
+
+\def\deftpx #1 {\errmessage{@deftpx in invalid context}}
+
+\message{cross reference,}
+% Define cross-reference macros
+\newwrite \auxfile
+
+\newif\ifhavexrefs % True if xref values are known.
+\newif\ifwarnedxrefs % True if we warned once that they aren't known.
+
+% \setref{foo} defines a cross-reference point named foo.
+
+\def\setref#1{%
+%\dosetq{#1-title}{Ytitle}%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Ysectionnumberandtype}}
+
+\def\unnumbsetref#1{%
+%\dosetq{#1-title}{Ytitle}%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Ynothing}}
+
+\def\appendixsetref#1{%
+%\dosetq{#1-title}{Ytitle}%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Yappendixletterandtype}}
+
+% \xref, \pxref, and \ref generate cross-references to specified points.
+% For \xrefX, #1 is the node name, #2 the name of the Info
+% cross-reference, #3 the printed node name, #4 the name of the Info
+% file, #5 the name of the printed manual. All but the node name can be
+% omitted.
+%
+\def\pxref#1{see \xrefX[#1,,,,,,,]}
+\def\xref#1{See \xrefX[#1,,,,,,,]}
+\def\ref#1{\xrefX[#1,,,,,,,]}
+\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup%
+\def\printedmanual{\ignorespaces #5}%
+\def\printednodename{\ignorespaces #3}%
+%
+\setbox1=\hbox{\printedmanual}%
+\setbox0=\hbox{\printednodename}%
+\ifdim \wd0=0pt%
+\def\printednodename{\ignorespaces #1}%
+%%% Uncommment the following line to make the actual chapter or section title
+%%% appear inside the square brackets.
+%\def\printednodename{#1-title}%
+\fi%
+%
+%
+% If we use \unhbox0 and \unhbox1 to print the node names, TeX does
+% not insert empty discretionaries after hyphens, which means that it
+% will not find a line break at a hyphen in a node names. Since some
+% manuals are best written with fairly long node names, containing
+% hyphens, this is a loss. Therefore, we simply give the text of
+% the node name again, so it is as if TeX is seeing it for the first
+% time.
+\ifdim \wd1>0pt
+section ``\printednodename'' in \cite{\printedmanual}%
+\else%
+\turnoffactive%
+\refx{#1-snt}{} [\printednodename], page\tie\refx{#1-pg}{}%
+\fi
+\endgroup}
+
+% \dosetq is the interface for calls from other macros
+
+% Use \turnoffactive so that punctuation chars such as underscore
+% work in node names.
+\def\dosetq #1#2{{\let\folio=0 \turnoffactive%
+\edef\next{\write\auxfile{\internalsetq {#1}{#2}}}%
+\next}}
+
+% \internalsetq {foo}{page} expands into
+% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...}
+% When the aux file is read, ' is the escape character
+
+\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}}
+
+% Things to be expanded by \internalsetq
+
+\def\Ypagenumber{\folio}
+
+\def\Ytitle{\thischapter}
+
+\def\Ynothing{}
+
+\def\Ysectionnumberandtype{%
+\ifnum\secno=0 Chapter\xreftie\the\chapno %
+\else \ifnum \subsecno=0 Section\xreftie\the\chapno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+Section\xreftie\the\chapno.\the\secno.\the\subsecno %
+\else %
+Section\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\def\Yappendixletterandtype{%
+\ifnum\secno=0 Appendix\xreftie'char\the\appendixno{}%
+\else \ifnum \subsecno=0 Section\xreftie'char\the\appendixno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno %
+\else %
+Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\gdef\xreftie{'tie}
+
+% Use TeX 3.0's \inputlineno to get the line number, for better error
+% messages, but if we're using an old version of TeX, don't do anything.
+%
+\ifx\inputlineno\thisisundefined
+ \let\linenumber = \empty % Non-3.0.
+\else
+ \def\linenumber{\the\inputlineno:\space}
+\fi
+
+% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME.
+% If its value is nonempty, SUFFIX is output afterward.
+
+\def\refx#1#2{%
+ \expandafter\ifx\csname X#1\endcsname\relax
+ % If not defined, say something at least.
+ $\langle$un\-de\-fined$\rangle$%
+ \ifhavexrefs
+ \message{\linenumber Undefined cross reference `#1'.}%
+ \else
+ \ifwarnedxrefs\else
+ \global\warnedxrefstrue
+ \message{Cross reference values unknown; you must run TeX again.}%
+ \fi
+ \fi
+ \else
+ % It's defined, so just use it.
+ \csname X#1\endcsname
+ \fi
+ #2% Output the suffix in any case.
+}
+
+% Read the last existing aux file, if any. No error if none exists.
+
+% This is the macro invoked by entries in the aux file.
+\def\xrdef #1#2{
+{\catcode`\'=\other\expandafter \gdef \csname X#1\endcsname {#2}}}
+
+\def\readauxfile{%
+\begingroup
+\catcode `\^^@=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\^^C=\other
+\catcode `\^^D=\other
+\catcode `\^^E=\other
+\catcode `\^^F=\other
+\catcode `\^^G=\other
+\catcode `\^^H=\other
+\catcode `\ =\other
+\catcode `\^^L=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode 26=\other
+\catcode `\^^[=\other
+\catcode `\^^\=\other
+\catcode `\^^]=\other
+\catcode `\^^^=\other
+\catcode `\^^_=\other
+\catcode `\@=\other
+\catcode `\^=\other
+\catcode `\~=\other
+\catcode `\[=\other
+\catcode `\]=\other
+\catcode`\"=\other
+\catcode`\_=\other
+\catcode`\|=\other
+\catcode`\<=\other
+\catcode`\>=\other
+\catcode `\$=\other
+\catcode `\#=\other
+\catcode `\&=\other
+% the aux file uses ' as the escape.
+% Turn off \ as an escape so we do not lose on
+% entries which were dumped with control sequences in their names.
+% For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^
+% Reference to such entries still does not work the way one would wish,
+% but at least they do not bomb out when the aux file is read in.
+\catcode `\{=1 \catcode `\}=2
+\catcode `\%=\other
+\catcode `\'=0
+\catcode `\\=\other
+\openin 1 \jobname.aux
+\ifeof 1 \else \closein 1 \input \jobname.aux \global\havexrefstrue
+\fi
+% Open the new aux file. Tex will close it automatically at exit.
+\openout \auxfile=\jobname.aux
+\endgroup}
+
+
+% Footnotes.
+
+\newcount \footnoteno
+
+\def\supereject{\par\penalty -20000\footnoteno =0 }
+
+% @footnotestyle is meaningful for info output only..
+\let\footnotestyle=\comment
+
+\let\ptexfootnote=\footnote
+
+{\catcode `\@=11
+\long\gdef\footnote #1{\global\advance \footnoteno by \@ne
+\unskip
+\edef\thisfootno{$^{\the\footnoteno}$}%
+\let\@sf\empty
+\ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi
+\thisfootno\@sf \footnotezzz{#1}}
+% \parsearg\footnotezzz}
+
+\long\gdef\footnotezzz #1{\insert\footins{
+\interlinepenalty\interfootnotelinepenalty
+\splittopskip\ht\strutbox % top baseline for broken footnotes
+\splitmaxdepth\dp\strutbox \floatingpenalty\@MM
+\leftskip\z@skip \rightskip\z@skip \spaceskip\z@skip \xspaceskip\z@skip
+\footstrut\parindent=\defaultparindent\hang\textindent{\thisfootno}#1\strut}}
+
+}%end \catcode `\@=11
+
+% End of control word definitions.
+
+\message{and turning on texinfo input format.}
+
+\def\openindices{%
+ \newindex{cp}%
+ \newcodeindex{fn}%
+ \newcodeindex{vr}%
+ \newcodeindex{tp}%
+ \newcodeindex{ky}%
+ \newcodeindex{pg}%
+}
+
+% Set some numeric style parameters, for 8.5 x 11 format.
+
+%\hsize = 6.5in
+\newdimen\defaultparindent \defaultparindent = 15pt
+\parindent = \defaultparindent
+\parskip 18pt plus 1pt
+\baselineskip 15pt
+\advance\topskip by 1.2cm
+
+% Prevent underfull vbox error messages.
+\vbadness=10000
+
+% Following George Bush, just get rid of widows and orphans.
+\widowpenalty=20000
+\clubpenalty=2000
+
+% Use TeX 3.0's \emergencystretch to help line breaking, but if we're
+% using an old version of TeX, don't do anything. We want the amount of
+% stretch added to depend on the line length, hence the dependence on
+% \hsize. This makes it come to about 9pt for the 8.5x11 format.
+%
+\ifx\emergencystretch\thisisundefined \else
+ \emergencystretch = \hsize
+ \divide\emergencystretch by 45
+\fi
+
+% Use @smallbook to reset parameters for 7x9.5 format (or else 7x9.25)
+\def\smallbook{
+\global\lispnarrowing = 0.3in
+\global\baselineskip 12pt
+\global\parskip 3pt plus 1pt
+\global\hsize = 5in
+\global\doublecolumnhsize=2.4in \global\doublecolumnvsize=15.0in
+\global\vsize=7.5in
+\global\tolerance=700
+\global\hfuzz=1pt
+\global\contentsrightmargin=0pt
+
+\global\pagewidth=\hsize
+\global\pageheight=\vsize
+
+\global\let\smalllisp=\smalllispx
+\global\let\smallexample=\smalllispx
+\global\def\Esmallexample{\Esmalllisp}
+}
+
+% Use @afourpaper to print on European A4 paper.
+\def\afourpaper{
+\global\tolerance=700
+\global\hfuzz=1pt
+\global\baselineskip=12pt
+\global\parskip 15pt plus 1pt
+
+\global\vsize= 53\baselineskip
+\advance\vsize by \topskip
+%\global\hsize= 5.85in % A4 wide 10pt
+\global\hsize= 6.5in
+\global\outerhsize=\hsize
+\global\advance\outerhsize by 0.5in
+\global\outervsize=\vsize
+\global\advance\outervsize by 0.6in
+\global\doublecolumnhsize=\hsize
+\global\divide\doublecolumnhsize by 2
+\global\advance\doublecolumnhsize by -0.1in
+\global\doublecolumnvsize=\vsize
+\global\multiply\doublecolumnvsize by 2
+\global\advance\doublecolumnvsize by 0.1in
+
+\global\pagewidth=\hsize
+\global\pageheight=\vsize
+}
+
+%% For a final copy, take out the rectangles
+%% that mark overfull boxes (in case you have decided
+%% that the text looks ok even though it passes the margin).
+\def\finalout{\overfullrule=0pt}
+
+% Define macros to output various characters with catcode for normal text.
+\catcode`\"=\other
+\catcode`\~=\other
+\catcode`\^=\other
+\catcode`\_=\other
+\catcode`\|=\other
+\catcode`\<=\other
+\catcode`\>=\other
+\catcode`\+=\other
+\def\normaldoublequote{"}
+\def\normaltilde{~}
+\def\normalcaret{^}
+\def\normalunderscore{_}
+\def\normalverticalbar{|}
+\def\normalless{<}
+\def\normalgreater{>}
+\def\normalplus{+}
+
+% This macro is used to make a character print one way in ttfont
+% where it can probably just be output, and another way in other fonts,
+% where something hairier probably needs to be done.
+%
+% #1 is what to print if we are indeed using \tt; #2 is what to print
+% otherwise. Since all the Computer Modern typewriter fonts have zero
+% interword stretch (and shrink), and it is reasonable to expect all
+% typewriter fonts to have this, we can check that font parameter.
+%
+\def\ifusingtt#1#2{\ifdim \fontdimen3\the\font=0pt #1\else #2\fi}
+
+% Turn off all special characters except @
+% (and those which the user can use as if they were ordinary).
+% Most of these we simply print from the \tt font, but for some, we can
+% use math or other variants that look better in normal text.
+
+\catcode`\"=\active
+\def\activedoublequote{{\tt \char '042}}
+\let"=\activedoublequote
+\catcode`\~=\active
+\def~{{\tt \char '176}}
+\chardef\hat=`\^
+\catcode`\^=\active
+\def^{{\tt \hat}}
+
+\catcode`\_=\active
+\def_{\ifusingtt\normalunderscore\_}
+% Subroutine for the previous macro.
+\def\_{\lvvmode \kern.06em \vbox{\hrule width.3em height.1ex}}
+
+% \lvvmode is equivalent in function to \leavevmode.
+% Using \leavevmode runs into trouble when written out to
+% an index file due to the expansion of \leavevmode into ``\unhbox
+% \voidb@x'' ---which looks to TeX like ``\unhbox \voidb\x'' due to our
+% magic tricks with @.
+\def\lvvmode{\vbox to 0pt{}}
+
+\catcode`\|=\active
+\def|{{\tt \char '174}}
+\chardef \less=`\<
+\catcode`\<=\active
+\def<{{\tt \less}}
+\chardef \gtr=`\>
+\catcode`\>=\active
+\def>{{\tt \gtr}}
+\catcode`\+=\active
+\def+{{\tt \char 43}}
+%\catcode 27=\active
+%\def^^[{$\diamondsuit$}
+
+% Used sometimes to turn off (effectively) the active characters
+% even after parsing them.
+\def\turnoffactive{\let"=\normaldoublequote
+\let~=\normaltilde
+\let^=\normalcaret
+\let_=\normalunderscore
+\let|=\normalverticalbar
+\let<=\normalless
+\let>=\normalgreater
+\let+=\normalplus}
+
+% Set up an active definition for =, but don't enable it most of the time.
+{\catcode`\==\active
+\global\def={{\tt \char 61}}}
+
+\catcode`\@=0
+
+% \rawbackslashxx output one backslash character in current font
+\global\chardef\rawbackslashxx=`\\
+%{\catcode`\\=\other
+%@gdef@rawbackslashxx{\}}
+
+% \rawbackslash redefines \ as input to do \rawbackslashxx.
+{\catcode`\\=\active
+@gdef@rawbackslash{@let\=@rawbackslashxx }}
+
+% \normalbackslash outputs one backslash in fixed width font.
+\def\normalbackslash{{\tt\rawbackslashxx}}
+
+% Say @foo, not \foo, in error messages.
+\escapechar=`\@
+
+% \catcode 17=0 % Define control-q
+\catcode`\\=\active
+
+% If a .fmt file is being used, we don't want the `\input texinfo' to show up.
+% That is what \eatinput is for; after that, the `\' should revert to printing
+% a backslash.
+%
+@gdef@eatinput input texinfo{@fixbackslash}
+@global@let\ = @eatinput
+
+% On the other hand, perhaps the file did not have a `\input texinfo'. Then
+% the first `\{ in the file would cause an error. This macro tries to fix
+% that, assuming it is called before the first `\' could plausibly occur.
+%
+@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi}
+
+%% These look ok in all fonts, so just make them not special. The @rm below
+%% makes sure that the current font starts out as the newly loaded cmr10
+@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other
+
+@textfonts
+@rm
+
+@c Local variables:
+@c page-delimiter: "^\\\\message"
+@c End:
diff --git a/gnu/usr.bin/cvs/contrib/rcs-to-cvs b/gnu/usr.bin/cvs/contrib/rcs-to-cvs
new file mode 100644
index 000000000000..1a241b9a33ef
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/rcs-to-cvs
@@ -0,0 +1,208 @@
+#!/bin/csh
+#
+# rcs-to-cvs,v 1.3 1992/04/10 03:04:25 berliner Exp
+# Contributed by Per Cederqvist <ceder@lysator.liu.se>.
+#
+# Copyright (c) 1989, Brian Berliner
+#
+# You may distribute under the terms of the GNU General Public License
+# as specified in the README file that comes with the CVS 1.0 kit.
+#
+#############################################################################
+# #
+# This script is used to check in sources that previously was under RCS or #
+# no source control system. #
+# #
+# Usage: rcs-to-cvs repository #
+# #
+# The repository is the directory where the sources should #
+# be deposited.
+# #
+# checkin traverses the current directory, ensuring that an #
+# identical directory structure exists in the repository directory. It #
+# then checks the files in in the following manner: #
+# #
+# 1) If the file doesn't yet exist, check it in #
+# as revision 0.1 #
+# #
+# The script also is somewhat verbose in letting the user know what is #
+# going on. It prints a diagnostic when it creates a new file, or updates #
+# a file that has been modified on the trunk. #
+# #
+#############################################################################
+
+set vbose = 0
+set message = ""
+set cvsbin = /usr/gnu/bin
+set rcsbin = /usr/gnu/bin
+set grep = /bin/grep
+set message_file = /usr/tmp/checkin.$$
+set got_one = 0
+
+if ( $#argv < 1 ) then
+ echo "Usage: rcs-to-cvs [-v] [-m message] [-f message_file] repository"
+ exit 1
+endif
+while ( $#argv )
+ switch ( $argv[1] )
+ case -v:
+ set vbose = 1
+ breaksw
+ case -m:
+ shift
+ echo $argv[1] > $message_file
+ set got_one = 1
+ breaksw
+ case -f:
+ shift
+ set message_file = $argv[1]
+ set got_one = 2
+ breaksw
+ default:
+ break
+ endsw
+ shift
+end
+if ( $#argv < 1 ) then
+ echo "Usage: rcs-to-cvs [-v] [-m message] [-f message_file] repository"
+ exit 1
+endif
+set repository = $argv[1]
+shift
+
+if ( ! $?CVSROOT ) then
+ echo "Please set the environmental variable CVSROOT to the root"
+ echo " of the tree you wish to update"
+ exit 1
+endif
+
+if ( $got_one == 0 ) then
+ echo "Please Edit this file to contain the RCS log information" >$message_file
+ echo "to be associated with this file (please remove these lines)">>$message_file
+ if ( $?EDITOR ) then
+ $EDITOR $message_file > /dev/tty
+ else
+ /usr/ucb/vi $message_file > /dev/tty
+ endif
+ set got_one = 1
+endif
+
+umask 22
+
+set update_dir = ${CVSROOT}/${repository}
+if ( -d SCCS ) then
+ echo SCCS files detected!
+ exit 1
+endif
+if ( -d RCS ) then
+ $rcsbin/co RCS/* >& /dev/null
+endif
+foreach name ( * .[a-zA-Z0-9]* )
+ echo $name
+ if ( "$name" == SCCS ) then
+ continue
+ endif
+ if ( "$name" == RCS ) then
+ continue
+ endif
+ if ( $vbose ) then
+ echo "Updating ${repository}/${name}"
+ endif
+ if ( -d "$name" ) then
+ if ( ! -d "${update_dir}/${name}" ) then
+ echo "WARNING: Creating new directory ${repository}/${name}"
+ mkdir "${update_dir}/${name}"
+ if ( $status ) then
+ echo "ERROR: mkdir failed - aborting"
+ exit 1
+ endif
+ endif
+ chdir "$name"
+ if ( $status ) then
+ echo "ERROR: Couldn\'t chdir to "$name" - aborting"
+ exit 1
+ endif
+ if ( $vbose ) then
+ rcs-to-cvs -v -f $message_file "${repository}/${name}"
+ else
+ rcs-to-cvs -f $message_file "${repository}/${name}"
+ endif
+ if ( $status ) then
+ exit 1
+ endif
+ chdir ..
+ else # if not directory
+ if ( ! -f "$name" ) then
+ echo "WARNING: "$name" is neither a regular file"
+ echo " nor a directory - ignored"
+ continue
+ endif
+ set file = "${update_dir}/${name},v"
+ set new = 0
+ set comment = ""
+ grep -s '\$Log.*\$' "${name}"
+ if ( $status == 0 ) then # If $Log keyword
+ set myext = ${name:e}
+ set knownext = 0
+ foreach xx ( "c" "csh" "e" "f" "h" "l" "mac" "me" "mm" "ms" "p" "r" "red" "s" "sh" "sl" "cl" "ml" "el" "tex" "y" "ye" "yr" "" )
+ if ( "${myext}" == "${xx}" ) then
+ set knownext = 1
+ break
+ endif
+ end
+ if ( $knownext == 0 ) then
+ echo For file ${file}:
+ grep '\$Log.*\$' "${name}"
+ echo -n "Please insert a comment leader for file ${name} > "
+ set comment = $<
+ endif
+ endif
+ if ( ! -f "$file" ) then # If not exists in repository
+ if ( ! -f "${update_dir}/Attic/${name},v" ) then
+ echo "WARNING: Creating new file ${repository}/${name}"
+ if ( -f RCS/"${name}",v ) then
+ echo "MSG: Copying old rcs file."
+ cp RCS/"${name}",v "$file"
+ else
+ if ( "${comment}" != "" ) then
+ $rcsbin/rcs -q -i -c"${comment}" -t${message_file} -m'.' "$file"
+ endif
+ $rcsbin/ci -q -u0.1 -t${message_file} -m'.' "$file"
+ if ( $status ) then
+ echo "ERROR: Initial check-in of $file failed - aborting"
+ exit 1
+ endif
+ set new = 1
+ endif
+ else
+ set file = "${update_dir}/Attic/${name},v"
+ echo "WARNING: IGNORED: ${repository}/Attic/${name}"
+ continue
+ endif
+ else # File existed
+ echo ERROR: File exists: Ignored: "$file"
+ continue
+# set headbranch = `sed -n '/^head/p; /^branch/p; 2q' $file`
+# if ( $#headbranch != 2 && $#headbranch != 4 ) then
+# echo "ERROR: corrupted RCS file $file - aborting"
+# endif
+# set head = "$headbranch[2]"
+# set branch = ""
+# if ( $#headbranch == 4 ) then
+# set branch = "$headbranch[4]"
+# endif
+# if ( "$head" == "1.1;" && "$branch" != "1.1.1;" ) then
+# ${rcsbin}/rcsdiff -q -r1.1 $file > /dev/null
+# if ( ! $status ) then
+# set new = 1
+# endif
+# else
+# if ( "$branch" != "1.1.1;" ) then
+# echo -n "WARNING: Updating locally modified file "
+# echo "${repository}/${name}"
+# endif
+# endif
+ endif
+ endif
+end
+if ( $got_one == 1 ) rm $message_file
diff --git a/gnu/usr.bin/cvs/contrib/rcslock.pl b/gnu/usr.bin/cvs/contrib/rcslock.pl
new file mode 100644
index 000000000000..db09b4bf2ade
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/rcslock.pl
@@ -0,0 +1,234 @@
+#!/usr/bin/perl
+
+# Author: John Rouillard (rouilj@cs.umb.edu)
+# Supported: Yeah right. (Well what do you expect for 2 hours work?)
+# Blame-to: rouilj@cs.umb.edu
+# Complaints to: Anybody except Brian Berliner, he's blameless for
+# this script.
+# Acknowlegements: The base code for this script has been acquired
+# from the log.pl script.
+
+# rcslock.pl - A program to prevent commits when a file to be ckecked
+# in is locked in the repository.
+
+# There are times when you need exclusive access to a file. This
+# often occurs when binaries are checked into the repository, since
+# cvs's (actually rcs's) text based merging mechanism won't work. This
+# script allows you to use the rcs lock mechanism (rcs -l) to make
+# sure that no changes to a repository are able to be committed if
+# those changes would result in a locked file being changed.
+
+# WARNING:
+# This script will work only if locking is set to strict.
+#
+
+# Setup:
+# Add the following line to the commitinfo file:
+
+# ALL /local/location/for/script/lockcheck [options]
+
+# Where ALL is replaced by any suitable regular expression.
+# Options are -v for verbose info, or -d for debugging info.
+# The %s will provide the repository directory name and the names of
+# all changed files.
+
+# Use:
+# When a developer needs exclusive access to a version of a file, s/he
+# should use "rcs -l" in the repository tree to lock the version they
+# are working on. CVS will automagically release the lock when the
+# commit is performed.
+
+# Method:
+# An "rlog -h" is exec'ed to give info on all about to be
+# committed files. This (header) information is parsed to determine
+# if any locks are outstanding and what versions of the file are
+# locked. This filename, version number info is used to index an
+# associative array. All of the files to be committed are checked to
+# see if any locks are outstanding. If locks are outstanding, the
+# version number of the current file (taken from the CVS/Entries
+# subdirectory) is used in the key to determine if that version is
+# locked. If the file being checked in is locked by the person doing
+# the checkin, the commit is allowed, but if the lock is held on that
+# version of a file by another person, the commit is not allowed.
+
+$ext = ",v"; # The extension on your rcs files.
+
+$\="\n"; # I hate having to put \n's at the end of my print statements
+$,=' '; # Spaces should occur between arguments to print when printed
+
+# turn off setgid
+#
+$) = $(;
+
+#
+# parse command line arguments
+#
+require 'getopts.pl';
+
+&Getopts("vd"); # verbose or debugging
+
+# Verbose is useful when debugging
+$opt_v = $opt_d if defined $opt_d;
+
+# $files[0] is really the name of the subdirectory.
+# @files = split(/ /,$ARGV[0]);
+@files = @ARGV[0..$#ARGV];
+$cvsroot = $ENV{'CVSROOT'};
+
+#
+# get login name
+#
+$login = getlogin || (getpwuid($<))[0] || "nobody";
+
+#
+# save the current directory since we have to return here to parse the
+# CVS/Entries file if a lock is found.
+#
+$pwd = `/bin/pwd`;
+chop $pwd;
+
+print "Starting directory is $pwd" if defined $opt_d ;
+
+#
+# cd to the repository directory and check on the files.
+#
+print "Checking directory ", $files[0] if defined $opt_v ;
+
+if ( $files[0] =~ /^\// )
+{
+ print "Directory path is $files[0]" if defined $opt_d ;
+ chdir $files[0] || die "Can't change to repository directory $files[0]" ;
+}
+else
+{
+ print "Directory path is $cvsroot/$files[0]" if defined $opt_d ;
+ chdir ($cvsroot . "/" . $files[0]) ||
+ die "Can't change to repository directory $files[0] in $cvsroot" ;
+}
+
+
+# Open the rlog process and apss all of the file names to that one
+# process to cut down on exec overhead. This may backfire if there
+# are too many files for the system buffer to handle, but if there are
+# that many files, chances are that the cvs repository is not set up
+# cleanly.
+
+print "opening rlog -h @files[1..$#files] |" if defined $opt_d;
+
+open( RLOG, "rlog -h @files[1..$#files] |") || die "Can't run rlog command" ;
+
+# Create the locks associative array. The elements in the array are
+# of two types:
+#
+# The name of the RCS file with a value of the total number of locks found
+# for that file,
+# or
+#
+# The name of the rcs file concatenated with the version number of the lock.
+# The value of this element is the name of the locker.
+
+# The regular expressions used to split the rcs info may have to be changed.
+# The current ones work for rcs 5.6.
+
+$lock = 0;
+
+while (<RLOG>)
+{
+ chop;
+ next if /^$/; # ditch blank lines
+
+ if ( $_ =~ /^RCS file: (.*)$/ )
+ {
+ $curfile = $1;
+ next;
+ }
+
+ if ( $_ =~ /^locks: strict$/ )
+ {
+ $lock = 1 ;
+ next;
+ }
+
+ if ( $lock )
+ {
+ # access list: is the line immediately following the list of locks.
+ if ( /^access list:/ )
+ { # we are done getting lock info for this file.
+ $lock = 0;
+ }
+ else
+ { # We are accumulating lock info.
+
+ # increment the lock count
+ $locks{$curfile}++;
+ # save the info on the version that is locked. $2 is the
+ # version number $1 is the name of the locker.
+ $locks{"$curfile" . "$2"} = $1
+ if /[ ]*([a-zA-Z._]*): ([0-9.]*)$/;
+
+ print "lock by $1 found on $curfile version $2" if defined $opt_d;
+
+ }
+ }
+}
+
+# Lets go back to the starting directory and see if any locked files
+# are ones we are interested in.
+
+chdir $pwd;
+
+# fo all of the file names (remember $files[0] is the directory name
+foreach $i (@files[1..$#files])
+{
+ if ( defined $locks{$i . $ext} )
+ { # well the file has at least one lock outstanding
+
+ # find the base version number of our file
+ &parse_cvs_entry($i,*entry);
+
+ # is our version of this file locked?
+ if ( defined $locks{$i . $ext . $entry{"version"}} )
+ { # if so, it is by us?
+ if ( $login ne ($by = $locks{$i . $ext . $entry{"version"}}) )
+ {# crud somebody else has it locked.
+ $outstanding_lock++ ;
+ print "$by has file $i locked for version " , $entry{"version"};
+ }
+ else
+ { # yeah I have it locked.
+ print "You have a lock on file $i for version " , $entry{"version"}
+ if defined $opt_v;
+ }
+ }
+ }
+}
+
+exit $outstanding_lock;
+
+
+### End of main program
+
+sub parse_cvs_entry
+{ # a very simple minded hack at parsing an entries file.
+local ( $file, *entry ) = @_;
+local ( @pp );
+
+
+open(ENTRIES, "< CVS/Entries") || die "Can't open entries file";
+
+while (<ENTRIES>)
+ {
+ if ( $_ =~ /^\/$file\// )
+ {
+ @pp = split('/');
+
+ $entry{"name"} = $pp[1];
+ $entry{"version"} = $pp[2];
+ $entry{"dates"} = $pp[3];
+ $entry{"name"} = $pp[4];
+ $entry{"name"} = $pp[5];
+ $entry{"sticky"} = $pp[6];
+ return;
+ }
+ }
+}
diff --git a/gnu/usr.bin/cvs/contrib/sccs2rcs b/gnu/usr.bin/cvs/contrib/sccs2rcs
new file mode 100644
index 000000000000..a208645aa68e
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/sccs2rcs
@@ -0,0 +1,277 @@
+#!/bin/csh -f
+#
+# Sccs2rcs is a script to convert an existing SCCS
+# history into an RCS history without losing any of
+# the information contained therein.
+# It has been tested under the following OS's:
+# SunOS 3.5, 4.0.3, 4.1
+# Ultrix-32 2.0, 3.1
+#
+# Things to note:
+# + It will NOT delete or alter your ./SCCS history under any circumstances.
+#
+# + Run in a directory where ./SCCS exists and where you can
+# create ./RCS
+#
+# + /usr/local/bin is put in front of the default path.
+# (SCCS under Ultrix is set-uid sccs, bad bad bad, so
+# /usr/local/bin/sccs here fixes that)
+#
+# + Date, time, author, comments, branches, are all preserved.
+#
+# + If a command fails somewhere in the middle, it bombs with
+# a message -- remove what it's done so far and try again.
+# "rm -rf RCS; sccs unedit `sccs tell`; sccs clean"
+# There is no recovery and exit is far from graceful.
+# If a particular module is hanging you up, consider
+# doing it separately; move it from the current area so that
+# the next run will have a better chance or working.
+# Also (for the brave only) you might consider hacking
+# the s-file for simpler problems: I've successfully changed
+# the date of a delta to be in sync, then run "sccs admin -z"
+# on the thing.
+#
+# + After everything finishes, ./SCCS will be moved to ./old-SCCS.
+#
+# This file may be copied, processed, hacked, mutilated, and
+# even destroyed as long as you don't tell anyone you wrote it.
+#
+# Ken Cox
+# Viewlogic Systems, Inc.
+# kenstir@viewlogic.com
+# ...!harvard!cg-atla!viewlog!kenstir
+#
+# Various hacks made by Brian Berliner before inclusion in CVS contrib area.
+#
+# sccs2rcs,v 1.1 1992/04/10 03:04:26 berliner Exp
+
+
+#we'll assume the user set up the path correctly
+# for the Pmax, /usr/ucb/sccs is suid sccs, what a pain
+# /usr/local/bin/sccs should override /usr/ucb/sccs there
+set path = (/usr/local/bin $path)
+
+
+############################################################
+# Error checking
+#
+if (! -w .) then
+ echo "Error: ./ not writeable by you."
+ exit 1
+endif
+if (! -d SCCS) then
+ echo "Error: ./SCCS directory not found."
+ exit 1
+endif
+set edits = (`sccs tell`)
+if ($#edits) then
+ echo "Error: $#edits file(s) out for edit...clean up before converting."
+ exit 1
+endif
+if (-d RCS) then
+ echo "Warning: RCS directory exists"
+ if (`ls -a RCS | wc -l` > 2) then
+ echo "Error: RCS directory not empty
+ exit 1
+ endif
+else
+ mkdir RCS
+endif
+
+sccs clean
+
+set logfile = /tmp/sccs2rcs_$$_log
+rm -f $logfile
+set tmpfile = /tmp/sccs2rcs_$$_tmp
+rm -f $tmpfile
+set emptyfile = /tmp/sccs2rcs_$$_empty
+echo -n "" > $emptyfile
+set initialfile = /tmp/sccs2rcs_$$_init
+echo "Initial revision" > $initialfile
+set sedfile = /tmp/sccs2rcs_$$_sed
+rm -f $sedfile
+set revfile = /tmp/sccs2rcs_$$_rev
+rm -f $revfile
+
+# the quotes surround the dollar signs to fool RCS when I check in this script
+set sccs_keywords = (\
+ '%W%[ ]*%G%'\
+ '%W%[ ]*%E%'\
+ '%W%'\
+ '%Z%%M%[ ]*%I%[ ]*%G%'\
+ '%Z%%M%[ ]*%I%[ ]*%E%'\
+ '%M%[ ]*%I%[ ]*%G%'\
+ '%M%[ ]*%I%[ ]*%E%'\
+ '%M%'\
+ '%I%'\
+ '%G%'\
+ '%E%'\
+ '%U%')
+set rcs_keywords = (\
+ '$'Id'$'\
+ '$'Id'$'\
+ '$'Id'$'\
+ '$'SunId'$'\
+ '$'SunId'$'\
+ '$'Id'$'\
+ '$'Id'$'\
+ '$'RCSfile'$'\
+ '$'Revision'$'\
+ '$'Date'$'\
+ '$'Date'$'\
+ '')
+
+
+############################################################
+# Get some answers from user
+#
+echo ""
+echo "Do you want to be prompted for a description of each"
+echo "file as it is checked in to RCS initially?"
+echo -n "(y=prompt for description, n=null description) [y] ?"
+set ans = $<
+if ((_$ans == _) || (_$ans == _y) || (_$ans == _Y)) then
+ set nodesc = 0
+else
+ set nodesc = 1
+endif
+echo ""
+echo "The default keyword substitutions are as follows and are"
+echo "applied in the order specified:"
+set i = 1
+while ($i <= $#sccs_keywords)
+# echo ' '\"$sccs_keywords[$i]\"' ==> '\"$rcs_keywords[$i]\"
+ echo " $sccs_keywords[$i] ==> $rcs_keywords[$i]"
+ @ i = $i + 1
+end
+echo ""
+echo -n "Do you want to change them [n] ?"
+set ans = $<
+if ((_$ans != _) && (_$ans != _n) && (_$ans != _N)) then
+ echo "You can't always get what you want."
+ echo "Edit this script file and change the variables:"
+ echo ' $sccs_keywords'
+ echo ' $rcs_keywords'
+else
+ echo "good idea."
+endif
+
+# create the sed script
+set i = 1
+while ($i <= $#sccs_keywords)
+ echo "s,$sccs_keywords[$i],$rcs_keywords[$i],g" >> $sedfile
+ @ i = $i + 1
+end
+
+onintr ERROR
+
+############################################################
+# Loop over every s-file in SCCS dir
+#
+foreach sfile (SCCS/s.*)
+ # get rid of the "s." at the beginning of the name
+ set file = `echo $sfile:t | sed -e "s/^..//"`
+
+ # work on each rev of that file in ascending order
+ set firsttime = 1
+ sccs prs $file | grep "^D " | awk '{print $2}' | sed -e 's/\./ /g' | sort -n -u +0 +1 +2 +3 +4 +5 +6 +7 +8 | sed -e 's/ /./g' > $revfile
+ foreach rev (`cat $revfile`)
+ if ($status != 0) goto ERROR
+
+ # get file into current dir and get stats
+ set date = `sccs prs -r$rev $file | grep "^D " | awk '{printf("19%s %s", $3, $4); exit}'`
+ set author = `sccs prs -r$rev $file | grep "^D " | awk '{print $5; exit}'`
+ echo ""
+ echo "==> file $file, rev=$rev, date=$date, author=$author"
+ sccs edit -r$rev $file >>& $logfile
+ if ($status != 0) goto ERROR
+ echo checked out of SCCS
+
+ # add RCS keywords in place of SCCS keywords
+ sed -f $sedfile $file > $tmpfile
+ if ($status != 0) goto ERROR
+ echo performed keyword substitutions
+ cp $tmpfile $file
+
+ # check file into RCS
+ if ($firsttime) then
+ set firsttime = 0
+ if ($nodesc) then
+ echo about to do ci
+ echo ci -f -r$rev -d"$date" -w$author -t$emptyfile $file
+ ci -f -r$rev -d"$date" -w$author -t$emptyfile $file < $initialfile >>& $logfile
+ if ($status != 0) goto ERROR
+ echo initial rev checked into RCS without description
+ else
+ echo ""
+ echo Enter a brief description of the file $file \(end w/ Ctrl-D\):
+ cat > $tmpfile
+ ci -f -r$rev -d"$date" -w$author -t$tmpfile $file < $initialfile >>& $logfile
+ if ($status != 0) goto ERROR
+ echo initial rev checked into RCS
+ endif
+ else
+ # get RCS lock
+ set lckrev = `echo $rev | sed -e 's/\.[0-9]*$//'`
+ if ("$lckrev" =~ [0-9]*.*) then
+ # need to lock the brach -- it is OK if the lock fails
+ rcs -l$lckrev $file >>& $logfile
+ else
+ # need to lock the trunk -- must succeed
+ rcs -l $file >>& $logfile
+ if ($status != 0) goto ERROR
+ endif
+ echo got lock
+ sccs prs -r$rev $file | grep "." > $tmpfile
+ # it's OK if grep fails here and gives status == 1
+ # put the delta message in $tmpfile
+ ed $tmpfile >>& $logfile <<EOF
+/COMMENTS
+1,.d
+w
+q
+EOF
+ ci -f -r$rev -d"$date" -w$author $file < $tmpfile >>& $logfile
+ if ($status != 0) goto ERROR
+ echo checked into RCS
+ endif
+ sccs unedit $file >>& $logfile
+ if ($status != 0) goto ERROR
+ end
+ rm -f $file
+end
+
+
+############################################################
+# Clean up
+#
+echo cleaning up...
+mv SCCS old-SCCS
+rm -f $tmpfile $emptyfile $initialfile $sedfile
+echo ===================================================
+echo " Conversion Completed Successfully"
+echo ""
+echo " SCCS history now in old-SCCS/"
+echo ===================================================
+set exitval = 0
+goto cleanup
+
+ERROR:
+foreach f (`sccs tell`)
+ sccs unedit $f
+end
+echo ""
+echo ""
+echo Danger\! Danger\!
+echo Some command exited with a non-zero exit status.
+echo Log file exists in $logfile.
+echo ""
+echo Incomplete history in ./RCS -- remove it
+echo Original unchanged history in ./SCCS
+set exitval = 1
+
+cleanup:
+# leave log file
+rm -f $tmpfile $emptyfile $initialfile $sedfile $revfile
+
+exit $exitval