diff options
Diffstat (limited to 'gnu/usr.bin/cvs/contrib')
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\}\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 |
