diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-12-19 09:21:45 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-12-19 09:21:45 +0000 |
commit | d2986da510e6c7e4505c75a4b3fbb1940b2ad08d (patch) | |
tree | ebc252891ef89551a9d2cde9e164ba9d3c3e64ef /gnu/usr.bin/cvs/contrib | |
parent | 2b1f6f285527e332944cd8a2802f26984978c7a9 (diff) |
raw import of cvs-1.6
Diffstat (limited to 'gnu/usr.bin/cvs/contrib')
36 files changed, 16251 insertions, 0 deletions
diff --git a/gnu/usr.bin/cvs/contrib/ChangeLog b/gnu/usr.bin/cvs/contrib/ChangeLog new file mode 100644 index 00000000000..f44f07e4206 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/ChangeLog @@ -0,0 +1,142 @@ +Sun Oct 1 02:02:57 1995 Peter Wemm <peter@haywire.dialix.com> + + * Makefile.in: supply a suffix rule to deal with .sh "source" + +Sat Jul 29 17:29:13 1995 James Kingdon <kingdon@harvey.cyclic.com> + + * log.pl: Use global options -Qq, not command options -Qq. + + * Makefile.in (install): Look for $(PROGS) and + $(CONTRIB_PROGS) in build dir, not srcdir. + +Fri Jul 28 19:48:45 1995 Paul Eggert <eggert@twinsun.com> + + * rcs2log.sh: Sync with latest Emacs snapshot. + +Thu Jul 27 20:29:30 1995 Jim Blandy <jimb@totoro.cyclic.com> + + * rcs2log.sh: import of initial WNT port work + +Fri Jul 14 22:38:44 1995 Jim Blandy <jimb@totoro.cyclic.com> + + * rcs-to-cvs.sh: Changes from David J. Mackenzie. + Set permissions on new repository files correctly. + Ignore *~ files. + +Thu Jul 13 23:04:12 CDT 1995 Jim Meyering (meyering@comco.com) + + * Makefile.in (.pl, .csh): *Never* redirect output directly to + the target (usu $@) of a rule. Instead, redirect to a temporary + file, and then move that temporary to the target. I chose to + name temporary files $@-t. Remember to be careful that the length + of the temporary file name not exceed the 14-character limit. + +Sun Jul 9 21:16:53 1995 Karl Fogel <kfogel@floss.cyclic.com> + + These are actually Greg Woods' changes: + + * clmerge.pl, cvscheck.sh, descend.sh, dirfns.shar, rcs-to-cvs.sh, + rcs2log.sh, sccs2rcs.csh: renamed from the corresponding files + sans extensions. + + * rcs2sccs.sh: new file. + +Sun Jul 9 19:03:00 1995 Greg A. Woods <woods@most.weird.com> + + * rcs2log.sh: oops, one more thing that should not have been + there. + - fix interpreter file syntax. + - remove "fix" for separating filenames and comments + + * Makefile.in: hmm... thought rcs2log was in RCS-5.7 for some + reason -- it's not, so we'll install it from here.... + - fix typo -- that's what you get for re-doing changes by hand! + - updates to support proper transformation and installation of + renamed files (from previous local changes) + + * .cvsignore: one more target noted... + + * sccs2rcs.csh: set up the interpreter file for updating by + Makefile (from previous local changes) + + * log_accum.pl, log.pl, commit_prep.pl: + - set up the interpreter file for updating by Makefile + - various modifications, updates, and enhancements + (from previous local changes) + + * rcslock.pl, mfpipe.pl, cvs_acls.pl, cln_hist.pl, clmerge.pl: + - set up the interpreter file for updating by Makefile + (from previous local changes) + - include changes from 1.5 here too, if any + + * README: + - remove extensions from filenames to match installed names + (from previous local changes) + + * .cvsignore: - added $(CONTRIB_PROGS) (from previous local changes) + + +Thu Jun 29 10:43:07 1995 James Kingdon <kingdon@harvey.cyclic.com> + + * Makefile.in (distclean): Also remove pcl-cvs/Makefile. + +Thu Jun 8 15:32:29 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * intro.doc: Added. + * Makefile.in (DISTFILES): Add intro.doc. + +Sat May 27 08:46:00 1995 Jim Meyering (meyering@comco.com) + + * Makefile.in (Makefile): Regenerate only Makefile in current + directory when Makefile.in is out of date. Depend on ../config.status. + +Mon May 8 13:06:29 1995 Bryan O'Sullivan <bos@serpentine.com> + + * README: added an entry for ccvs-rsh.pl. + +Sun Apr 30 23:50:32 1995 Bryan O'Sullivan <bos@serpentine.com> + + * ccvs-rsh.pl: fixed a typo and added more flexible use of + CVS_PROXY_USER. + +Sun Apr 30 14:56:21 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> + + * clmerge: Changes from Tom Tromey --- fix bug in date comparison + function. + +Sat Apr 29 20:53:08 1995 Bryan O'Sullivan <bos@serpentine.com> + + * ccvs-rsh.pl: created. See the file itself for documentation. + + * Makefile.in (DISTFILES): added ccvs-rsh.pl to the list of + files to install. + +Fri Apr 28 22:32:45 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> + + * Makefile.in (DISTFILES): Brought up-to-date with current + directory contents. + (dist-dir): Renamed from dist-dir; use DISTDIR variable, passed + from parent. + +Mon Feb 13 13:32:07 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> + + * rcs2log: rcs2log was originally in this tree; how did it get + deleted? Anyway, this is the version distributed with Emacs + 19.28, hacked to support CVS and Remote CVS. + +Mon Jul 26 13:18:23 1993 David J. Mackenzie (djm@thepub.cygnus.com) + + * rcs-to-cvs: Rewrite in sh. + +Wed Jul 14 21:16:40 1993 David J. Mackenzie (djm@thepub.cygnus.com) + + * rcs-to-cvs: Don't source .cshrc or hardcode paths. + Make respository dir if needed. Don't suppress errors + (such as prompts) from co. + +Wed Feb 26 18:04:40 1992 K. Richard Pixley (rich@cygnus.com) + + * Makefile.in, configure.in: removed traces of namesubdir, + -subdirs, $(subdir), $(unsubdir), some rcs triggers. Forced + copyrights to '92, changed some from Cygnus to FSF. + diff --git a/gnu/usr.bin/cvs/contrib/Makefile.in b/gnu/usr.bin/cvs/contrib/Makefile.in new file mode 100644 index 00000000000..2f16973daf4 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/Makefile.in @@ -0,0 +1,133 @@ +# Makefile for GNU CVS contributed sources. +# Do not use this makefile directly, but only from `../Makefile'. +# Copyright (C) 1986, 1988-1990 Free Software Foundation, Inc. + +# 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, 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. + +# $CVSid: @(#)Makefile.in 1.6 94/10/22 $ + +SHELL = /bin/sh + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +# Where to install the executables. +bindir = $(exec_prefix)/bin + +# Where to put the system-wide .cvsrc file +libdir = $(prefix)/lib + +# Where to put the manual pages. +mandir = $(prefix)/man + +# where to find command interpreters +perl_path = @perl_path@ +csh_path = @csh_path@ + +# Use cp if you don't have install. +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ + +DISTFILES = \ + ChangeLog README .cvsignore intro.doc \ + Makefile.in clmerge.pl cln_hist.pl commit_prep.pl cvs_acls.pl \ + cvscheck.sh cvscheck.man cvshelp.man descend.sh descend.man \ + dirfns.shar log.pl log_accum.pl mfpipe.pl rcs-to-cvs.sh rcs2log.sh \ + rcslock.pl sccs2rcs.csh + +# files installed in $(libdir)/cvs/contrib +# +CONTRIB_FILES = README intro.doc cvscheck.man + +# things we actually build and install.... +# +PROGS = rcs2log +CONTRIB_PROGS = clmerge cln_hist commit_prep cvs_acls cvscheck log log_accum \ + mfpipe rcs-to-cvs rcs2log rcslock sccs2rcs + +.SUFFIXES: .pl .sh .csh + +.pl: + rm -f $@ + sed -e 's,xPERL_PATHx,$(perl_path),' $< > $@-t + mv $@-t $@ + chmod +x $@ + +.csh: + rm -f $@ + sed -e 's,xCSH_PATHx,$(csh_path),' $< > $@-t + mv $@-t $@ + chmod +x $@ + +.sh: + rm -f $@ + cp $< $@ + chmod +x $@ + +all: Makefile $(PROGS) $(CONTRIB_PROGS) +.PHONY: all + +install: all $(libdir)/cvs/contrib + for f in $(CONTRIB_FILES) ; do\ + $(INSTALL_DATA) $(srcdir)/$$f $(libdir)/cvs/contrib/$$f; \ + done + for f in $(CONTRIB_PROGS) ; do\ + $(INSTALL_PROGRAM) $$f $(libdir)/cvs/contrib/$$f; \ + done + for f in $(PROGS) ; do\ + $(INSTALL_PROGRAM) $$f $(bindir)/$$f; \ + done +.PHONY: install + +$(libdir)/cvs/contrib: + $(top_srcdir)/mkinstalldirs $(libdir)/cvs/contrib + +tags: +.PHONY: tags + +TAGS: +.PHONY: TAGS + +ls: + @echo $(DISTFILES) +.PHONY: ls + +clean: + /bin/rm -f *.o core +.PHONY: clean + +distclean: clean + rm -f Makefile pcl-cvs/Makefile $(PROGS) $(CONTRIB_PROGS) +.PHONY: distclean + +realclean: distclean +.PHONY: realclean + +dist-dir: + mkdir ${DISTDIR} + for i in ${DISTFILES}; do \ + ln $(srcdir)/$${i} ${DISTDIR}; \ + done + cd pcl-cvs; ${MAKE} dist-dir DISTDIR="../${DISTDIR}/pcl-cvs" +.PHONY: dist-dir + +subdir = contrib +Makefile: ../config.status Makefile.in + cd .. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status diff --git a/gnu/usr.bin/cvs/contrib/README b/gnu/usr.bin/cvs/contrib/README new file mode 100644 index 00000000000..7ec14547022 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/README @@ -0,0 +1,90 @@ +$CVSid: @(#)README 1.12 94/09/25 $ + +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 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 A perl script, to be combined with log_accum.pl, to + log_accum 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 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 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>. + ccvs-rsh A Perl script which allows "rsh pipelines" to + be built in order to use Cyclic CVS from + behind some varieties of firewall. + cvs_acls 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 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> + sccs2rcs A C-shell script that can convert (some) SCCS files + into RCS files, retaining the info contained in the + SCCS file (like dates, author, and log message). + Contributed by Ken Cox <kenstir@viewlogic.com>. + intro.doc A user's view of what you need to know to get + started with CVS. + Contributed by <Steven.Pemberton@cwi.nl>. + rcs2sccs A shell script to convert simple RCS files into + SCCS files, originally gleaned off the network + somewhere (originally by "kenc") and modified by + Jerry Jelinek <jerry@rmtc.Central.Sun.COM> and + Brian Berliner <berliner@sun.com> to increase + robustness and add support for one-level of branches. + rcs2log A shell script to create a ChangeLog-format file + given only a set of RCS files. + Contributed by Paul Eggert <eggert@twinsun.com>. + clmerge A perl script to handle merge conflicts in GNU + style ChangeLog files . + Contributed by Tom Tromey <tromey@busco.lanl.gov>. diff --git a/gnu/usr.bin/cvs/contrib/clmerge.pl b/gnu/usr.bin/cvs/contrib/clmerge.pl new file mode 100644 index 00000000000..ac813713a82 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/clmerge.pl @@ -0,0 +1,152 @@ +#! xPERL_PATHx + +# Merge conflicted ChangeLogs +# tromey Mon Aug 15 1994 + +# Usage is: +# +# cl-merge [-i] file ... +# +# With -i, it works in place (backups put in a ~ file). Otherwise the +# merged ChangeLog is printed to stdout. + +# Please report any bugs to me. I wrote this yesterday, so there are no +# guarantees about its performance. I recommend checking its output +# carefully. If you do send a bug report, please include the failing +# ChangeLog, so I can include it in my test suite. +# +# Tom +# --- +# tromey@busco.lanl.gov Member, League for Programming Freedom +# Sadism and farce are always inexplicably linked. +# -- Alexander Theroux + + +# Month->number mapping. Used for sorting. +%months = ('Jan', 0, + 'Feb', 1, + 'Mar', 2, + 'Apr', 3, + 'May', 4, + 'Jun', 5, + 'Jul', 6, + 'Aug', 7, + 'Sep', 8, + 'Oct', 9, + 'Nov', 10, + 'Dec', 11); + +# If '-i' is given, do it in-place. +if ($ARGV[0] eq '-i') { + shift (@ARGV); + $^I = '~'; +} + +$lastkey = ''; +$lastval = ''; +$conf = 0; +%conflist = (); + +$tjd = 0; + +# Simple state machine. The states: +# +# 0 Not in conflict. Just copy input to output. +# 1 Beginning an entry. Next non-blank line is key. +# 2 In entry. Entry beginner transitions to state 1. +while (<>) { + if (/^<<<</ || /^====/) { + # Start of a conflict. + + # Copy last key into array. + if ($lastkey ne '') { + $conflist{$lastkey} = $lastval; + + $lastkey = ''; + $lastval = ''; + } + + $conf = 1; + } elsif (/^>>>>/) { + # End of conflict. Output. + + # Copy last key into array. + if ($lastkey ne '') { + $conflist{$lastkey} = $lastval; + + $lastkey = ''; + $lastval = ''; + } + + foreach (reverse sort clcmp keys %conflist) { + print STDERR "doing $_" if $tjd; + print $_; + print $conflist{$_}; + } + + $lastkey = ''; + $lastval = ''; + $conf = 0; + %conflist = (); + } elsif ($conf == 1) { + # Beginning an entry. Skip empty lines. Error if not a real + # beginner. + if (/^$/) { + # Empty line; just skip at this point. + } elsif (/^[MTWFS]/) { + # Looks like the name of a day; assume opener and move to + # "in entry" state. + $lastkey = $_; + $conf = 2; + print STDERR "found $_" if $tjd; + } else { + die ("conflict crosses entry boundaries: $_"); + } + } elsif ($conf == 2) { + # In entry. Copy into variable until we see beginner line. + if (/^[MTWFS]/) { + # Entry beginner line. + + # Copy last key into array. + if ($lastkey ne '') { + $conflist{$lastkey} = $lastval; + + $lastkey = ''; + $lastval = ''; + } + + $lastkey = $_; + print STDERR "found $_" if $tjd; + $lastval = ''; + } else { + $lastval .= $_; + } + } else { + # Just copy. + print; + } +} + +# Compare ChangeLog time strings like <=>. +# +# 0 1 2 3 +# Thu Aug 11 13:22:42 1994 Tom Tromey (tromey@creche.colorado.edu) +# 0123456789012345678901234567890 +# +sub clcmp { + # First check year. + $r = substr ($a, 20, 4) <=> substr ($b, 20, 4); + + # Now check month. + $r = $months{substr ($a, 4, 3)} <=> $months{substr ($b, 4, 3)} if !$r; + + # Now check day. + $r = substr ($a, 8, 2) <=> substr ($b, 8, 2) if !$r; + + # Now check time (3 parts). + $r = substr ($a, 11, 2) <=> substr ($b, 11, 2) if !$r; + $r = substr ($a, 14, 2) <=> substr ($b, 14, 2) if !$r; + $r = substr ($a, 17, 2) <=> substr ($b, 17, 2) if !$r; + + $r; +} 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 00000000000..7724331ba48 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/cln_hist.pl @@ -0,0 +1,92 @@ +#! xPERL_PATHx +# -*-Perl-*- +# +# $Id: cln_hist.pl,v 1.1 1995/12/19 09:21:39 deraadt 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 00000000000..61e20055919 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/commit_prep.pl @@ -0,0 +1,216 @@ +#! xPERL_PATHx +# -*-Perl-*- +# +#ident "@(#)cvs/contrib:$Name: $:$Id: commit_prep.pl,v 1.1 1995/12/19 09:21:39 deraadt Exp $" +# +# 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_accum.pl script. For new files, it forces 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. [[ bad idea! -- woods ]] +# +# +# Contributed by David Hampton <hampton@cisco.com> +# +# Hacked on lots by Greg A. Woods <woods@web.net> + +# +# Configurable options +# + +# Constants (remember to protect strings from RCS keyword substitution) +# +$LAST_FILE = "/tmp/#cvs.lastdir"; # must match name in log_accum.pl +$ENTRIES = "CVS/Entries"; + +# Patterns to find $Log keywords in files +# +$LogString1 = "\\\$\\Log: .* \\\$"; +$LogString2 = "\\\$\\Log\\\$"; +$NoLog = "%s - contains an RCS \$Log keyword. It must not!\n"; + +# pattern to match an RCS Id keyword line with an existing ID +# +$IDstring = "\"@\\(#\\)[^:]*:.*\\\$\Id: .*\\\$\""; +$NoId = " +%s - Does not contain a properly formatted line with the keyword \"Id:\". + I.e. no lines match \"" . $IDstring . "\". + Please see the template files for an example.\n"; + +# pattern to match an RCS Id keyword line for a new file (i.e. un-expanded) +# +$NewId = "\"@(#)[^:]*:.*\\$\Id\\$\""; + +$NoName = " +%s - The ID line should contain only \"@(#)module/path:\$Name\$:\$\Id\$\" + 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, then try the commit again.\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") || return(0); + + @all_lines = (); + $idpos = -1; + $newidpos = -1; + for ($i = 0; <FILE>; $i++) { + chop; + push(@all_lines, $_); + if ($_ =~ /$IDstring/) { + $idpos = $i; + } + if ($_ =~ /$NewId/) { + $newidpos = $i; + } + } + + if (grep(/$LogString1/, @all_lines) || grep(/$LogString2/, @all_lines)) { + print STDERR sprintf($NoLog, $filename); + return(1); + } + + if ($debug != 0) { + print STDERR sprintf("file = %s, version = %d.\n", $filename, $cvsversion{$filename}); + } + + if ($cvsversion{$filename} == 0) { + if ($newidpos != -1 && $all_lines[$newidpos] !~ /$NewId/) { + print STDERR sprintf($NoName, $filename); + return(1); + } + return(0); + } + + if ($idpos == -1) { + print STDERR sprintf($NoId, $filename); + return(1); + } + + $line = $all_lines[$idpos]; + $pos = index($line, "Id: "); + if ($debug != 0) { + print STDERR sprintf("%d in '%s'.\n", $pos, $line); + } + ($id, $rname, $version) = split(' ', substr($line, $pos)); + if ($rname ne "$filename,v") { + print STDERR sprintf($BadName, $filename, substr($rname, 0, length($rname)-2)); + return(1); + } + if ($cvsversion{$filename} < $version) { + print STDERR sprintf($BadVersion, $filename, $filename, $cvsversion{$filename}, + "newer", $version, $filename); + return(1); + } + if ($cvsversion{$filename} > $version) { + print STDERR sprintf($BadVersion, $filename, $filename, $cvsversion{$filename}, + "older", $version, $filename); + return(1); + } + return(0); +} + +# +# Main Body +# + +$id = getpgrp(); # You *must* use a shell that does setpgrp()! + +# Check each file (except dot files) for an RCS "Id" keyword. +# +$check_id = 0; + +# Record the directory for later use by the log_accumulate stript. +# +$record_directory = 0; + +# parse command line arguments +# +while (@ARGV) { + $arg = shift @ARGV; + + if ($arg eq '-d') { + $debug = 1; + print STDERR "Debug turned on...\n"; + } elsif ($arg eq '-c') { + $check_id = 1; + } elsif ($arg eq '-r') { + $record_directory = 1; + } else { + push(@files, $arg); + } +} + +$directory = shift @files; + +if ($debug != 0) { + print STDERR "dir - ", $directory, "\n"; + print STDERR "files - ", join(":", @files), "\n"; + print STDERR "id - ", $id, "\n"; +} + +# Suck in the CVS/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; + foreach $arg (@files) { + if (index($arg, ".") == 0) { + next; + } + $failed += &check_version($arg); + } + if ($failed) { + print STDERR "\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 00000000000..9149a604801 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/cvs_acls.pl @@ -0,0 +1,143 @@ +#! xPERL_PATHx +# -*-Perl-*- +# +# $Id: cvs_acls.pl,v 1.1 1995/12/19 09:21:39 deraadt 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.man b/gnu/usr.bin/cvs/contrib/cvscheck.man new file mode 100644 index 00000000000..a9537cb87de --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/cvscheck.man @@ -0,0 +1,53 @@ +.\" $Id: cvscheck.man,v 1.1.1.1 1995/12/19 09:21:39 deraadt 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/cvscheck.sh b/gnu/usr.bin/cvs/contrib/cvscheck.sh new file mode 100644 index 00000000000..bc33d7972e2 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/cvscheck.sh @@ -0,0 +1,84 @@ +#! /bin/sh +# $Id: cvscheck.sh,v 1.1.1.1 1995/12/19 09:21:39 deraadt 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/cvshelp.man b/gnu/usr.bin/cvs/contrib/cvshelp.man new file mode 100644 index 00000000000..cf6ccb78210 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/cvshelp.man @@ -0,0 +1,562 @@ +.\" $Id: cvshelp.man,v 1.1.1.1 1995/12/19 09:21:40 deraadt 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.man b/gnu/usr.bin/cvs/contrib/descend.man new file mode 100644 index 00000000000..ef5b2bbdc61 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/descend.man @@ -0,0 +1,115 @@ +.\" $Id: descend.man,v 1.1.1.1 1995/12/19 09:21:40 deraadt 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/descend.sh b/gnu/usr.bin/cvs/contrib/descend.sh new file mode 100644 index 00000000000..f3a1790be7d --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/descend.sh @@ -0,0 +1,116 @@ +#! /bin/sh +# $Id: descend.sh,v 1.1.1.1 1995/12/19 09:21:40 deraadt 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/dirfns.shar b/gnu/usr.bin/cvs/contrib/dirfns.shar new file mode 100644 index 00000000000..8324c4198e3 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/dirfns.shar @@ -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/intro.doc b/gnu/usr.bin/cvs/contrib/intro.doc new file mode 100644 index 00000000000..a6d4ec12338 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/intro.doc @@ -0,0 +1,112 @@ +Date: Tue, 16 Jun 1992 17:05:23 +0200 +From: Steven.Pemberton@cwi.nl +Message-Id: <9206161505.AA06927.steven@sijs.cwi.nl> +To: berliner@Sun.COM +Subject: cvs + +INTRODUCTION TO USING CVS + + CVS is a system that lets groups of people work simultaneously on + groups of files (for instance program sources). + + It works by holding a central 'repository' of the most recent version + of the files. You may at any time create a personal copy of these + files; if at a later date newer versions of the files are put in the + repository, you can 'update' your copy. + + You may edit your copy of the files freely. If new versions of the + files have been put in the repository in the meantime, doing an update + merges the changes in the central copy into your copy. + (It can be that when you do an update, the changes in the + central copy clash with changes you have made in your own + copy. In this case cvs warns you, and you have to resolve the + clash in your copy.) + + When you are satisfied with the changes you have made in your copy of + the files, you can 'commit' them into the central repository. + (When you do a commit, if you haven't updated to the most + recent version of the files, cvs tells you this; then you have + to first update, resolve any possible clashes, and then redo + the commit.) + +USING CVS + + Suppose that a number of repositories have been stored in + /usr/src/cvs. Whenever you use cvs, the environment variable + CVSROOT must be set to this (for some reason): + + CVSROOT=/usr/src/cvs + export CVSROOT + +TO CREATE A PERSONAL COPY OF A REPOSITORY + + Suppose you want a copy of the files in repository 'views' to be + created in your directory src. Go to the place where you want your + copy of the directory, and do a 'checkout' of the directory you + want: + + cd $HOME/src + cvs checkout views + + This creates a directory called (in this case) 'views' in the src + directory, containing a copy of the files, which you may now work + on to your heart's content. + +TO UPDATE YOUR COPY + + Use the command 'cvs update'. + + This will update your copy with any changes from the central + repository, telling you which files have been updated (their names + are displayed with a U before them), and which have been modified + by you and not yet committed (preceded by an M). You will be + warned of any files that contain clashes, the clashes will be + marked in the file surrounded by lines of the form <<<< and >>>>. + +TO COMMIT YOUR CHANGES + + Use the command 'cvs commit'. + + You will be put in an editor to make a message that describes the + changes that you have made (for future reference). Your changes + will then be added to the central copy. + +ADDING AND REMOVING FILES + + It can be that the changes you want to make involve a completely + new file, or removing an existing one. The commands to use here + are: + + cvs add <filename> + cvs remove <filename> + + You still have to do a commit after these commands. You may make + any number of new files in your copy of the repository, but they + will not be committed to the central copy unless you do a 'cvs add'. + +OTHER USEFUL COMMANDS AND HINTS + + To see the commit messages for files, and who made them, use: + + cvs log [filenames] + + To see the differences between your version and the central version: + + cvs diff [filenames] + + To give a file a new name, rename it and do an add and a remove. + + To lose your changes and go back to the version from the + repository, delete the file and do an update. + + After an update where there have been clashes, your original + version of the file is saved as .#file.version. + + All the cvs commands mentioned accept a flag '-n', that doesn't do + the action, but lets you see what would happen. For instance, you + can use 'cvs -n update' to see which files would be updated. + +MORE INFORMATION + + This is necessarily a very brief introduction. See the manual page + (man cvs) for full details. diff --git a/gnu/usr.bin/cvs/contrib/log.pl b/gnu/usr.bin/cvs/contrib/log.pl new file mode 100644 index 00000000000..51f759cc4c5 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/log.pl @@ -0,0 +1,167 @@ +#! xPERL_PATHx +# -*-Perl-*- +# +# XXX: FIXME: handle multiple '-f logfile' arguments +# +# XXX -- I HATE Perl! This will be re-written in shell/awk/sed soon! +# + +# Usage: log.pl [[-m user] ...] [-s] -f logfile 'dirname file ...' +# +# -m user - for each user to receive cvs log reports +# (multiple -m's permitted) +# -s - to prevent "cvs status -v" messages +# -f logfile - for the logfile to append to (mandatory, +# but only one logfile can be specified). + +# here is what the output looks like: +# +# From: woods@kuma.domain.top +# Subject: CVS update: testmodule +# +# Date: Wednesday November 23, 1994 @ 14:15 +# Author: woods +# +# Update of /local/src-CVS/testmodule +# In directory kuma:/home/kuma/woods/work.d/testmodule +# +# Modified Files: +# test3 +# Added Files: +# test6 +# Removed Files: +# test4 +# Log Message: +# - wow, what a test +# +# (and for each file the "cvs status -v" output is appended unless -s is used) +# +# ================================================================== +# File: test3 Status: Up-to-date +# +# Working revision: 1.41 Wed Nov 23 14:15:59 1994 +# Repository revision: 1.41 /local/src-CVS/cvs/testmodule/test3,v +# Sticky Options: -ko +# +# Existing Tags: +# local-v2 (revision: 1.7) +# local-v1 (revision: 1.1.1.2) +# CVS-1_4A2 (revision: 1.1.1.2) +# local-v0 (revision: 1.2) +# CVS-1_4A1 (revision: 1.1.1.1) +# CVS (branch: 1.1.1) + +$cvsroot = $ENV{'CVSROOT'}; + +# turn off setgid +# +$) = $(; + +$dostatus = 1; + +# parse command line arguments +# +while (@ARGV) { + $arg = shift @ARGV; + + if ($arg eq '-m') { + $users = "$users " . shift @ARGV; + } elsif ($arg eq '-f') { + ($logfile) && die "Too many '-f' args"; + $logfile = shift @ARGV; + } elsif ($arg eq '-s') { + $dostatus = 0; + } else { + ($donefiles) && die "Too many arguments!\n"; + $donefiles = 1; + @files = split(/ /, $arg); + } +} + +# the first argument is the module location relative to $CVSROOT +# +$modulepath = shift @files; + +$mailcmd = "| Mail -s 'CVS update: $modulepath'"; + +# Initialise 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 a login name for the guy doing the commit.... +# +$login = getlogin || (getpwuid($<))[0] || "nobody"; + +# open log file for appending +# +open(OUT, ">>" . $logfile) || die "Could not open(" . $logfile . "): $!\n"; + +# send mail, if there's anyone to send to! +# +if ($users) { + $mailcmd = "$mailcmd $users"; + open(MAIL, $mailcmd) || die "Could not Exec($mailcmd): $!\n"; +} + +# print out the log Header +# +print OUT "\n"; +print OUT "****************************************\n"; +print OUT "Date:\t$days[$wday] $mos[$mon] $mday, 19$year @ $hour:" . sprintf("%02d", $min) . "\n"; +print OUT "Author:\t$login\n\n"; + +if (MAIL) { + print MAIL "\n"; + print MAIL "Date:\t$days[$wday] $mos[$mon] $mday, 19$year @ $hour:" . sprintf("%02d", $min) . "\n"; + print MAIL "Author:\t$login\n\n"; +} + +# print the stuff from logmsg that comes in on stdin to the logfile +# +open(IN, "-"); +while (<IN>) { + print OUT $_; + if (MAIL) { + print MAIL $_; + } +} +close(IN); + +print OUT "\n"; + +# after log information, do an 'cvs -Qqv status' on each file in the arguments. +# +if ($dostatus != 0) { + while (@files) { + $file = shift @files; + if ($file eq "-") { + print OUT "[input file was '-']\n"; + if (MAIL) { + print MAIL "[input file was '-']\n"; + } + last; + } + open(RCS, "-|") || exec 'cvs', '-nQq', 'status', '-v', $file; + while (<RCS>) { + print OUT; + if (MAIL) { + print MAIL; + } + } + close(RCS); + } +} + +close(OUT); +die "Write to $logfile failed" if $?; + +close(MAIL); +die "Pipe to $mailcmd failed" if $?; + +## must exit cleanly +## +exit 0; 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 00000000000..1b38033d430 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/log_accum.pl @@ -0,0 +1,492 @@ +#! xPERL_PATHx +# -*-Perl-*- +# +# 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> +# +# hacked greatly by Greg A. Woods <woods@web.net> + +# Usage: log_accum.pl [-d] [-s] [-M module] [[-m mailto] ...] [-f logfile] +# -d - turn on debugging +# -m mailto - send mail to "mailto" (multiple) +# -M modulename - set module name to "modulename" +# -f logfile - write commit messages to logfile too +# -s - *don't* run "cvs status -v" for each file + +# +# Configurable options +# + +$MAILER = "Mail"; # set this to something that takes "-s" + +# Constants (don't change these!) +# +$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"; + +# +# Subroutines +# + +sub cleanup_tmpfiles { + local($wd, @files); + + $wd = `pwd`; + chdir("/tmp") || die("Can't chdir('/tmp')\n"); + opendir(DIR, "."); + push(@files, grep(/^$FILE_PREFIX\..*\.$id$/, readdir(DIR))); + closedir(DIR); + foreach (@files) { + unlink $_; + } + unlink $LAST_FILE . "." . $id; + + 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_logfile { + local($filename, @lines) = @_; + + open(FILE, ">$filename") || die("Cannot open log file $filename.\n"); + print FILE join("\n", @lines), "\n"; + close(FILE); +} + +sub format_names { + local($dir, @files) = @_; + local(@lines); + + $format = "\t%-" . sprintf("%d", length($dir)) . "s%s "; + + $lines[0] = sprintf($format, $dir, ":"); + + if ($debug) { + print STDERR "format_names(): dir = ", $dir, "; files = ", join(":", @files), ".\n"; + } + foreach $file (@files) { + if (length($lines[$#lines]) + length($file) > 65) { + $lines[++$#lines] = sprintf($format, " ", " "); + } + $lines[$#lines] .= $file . " "; + } + + @lines; +} + +sub format_lists { + local(@lines) = @_; + local(@text, @files, $lastdir); + + if ($debug) { + print STDERR "format_lists(): ", join(":", @lines), "\n"; + } + @text = (); + @files = (); + $lastdir = shift @lines; # first thing is always a directory + if ($lastdir !~ /.*\/$/) { + die("Damn, $lastdir doesn't look like a directory!\n"); + } + foreach $line (@lines) { + if ($line =~ /.*\/$/) { + push(@text, &format_names($lastdir, @files)); + $lastdir = $line; + @files = (); + } else { + push(@files, $line); + } + } + push(@text, &format_names($lastdir, @files)); + + @text; +} + +sub append_names_to_file { + local($filename, $dir, @files) = @_; + + if (@files) { + open(FILE, ">>$filename") || die("Cannot open file $filename.\n"); + print FILE $dir, "\n"; + print FILE join("\n", @files), "\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_logfile { + local(@text); + local($filename, $leader) = @_; + + open(FILE, "<$filename"); + while (<FILE>) { + chop; + push(@text, $leader.$_); + } + close(FILE); + @text; +} + +sub build_header { + local($header); + local($sec,$min,$hour,$mday,$mon,$year) = localtime(time); + $header = sprintf("CVSROOT:\t%s\nModule name:\t%s\nChanges by:\t%s@%s\t%02d/%02d/%02d %02d:%02d:%02d", + $cvsroot, + $modulename, + $login, $hostdomain, + $year%100, $mon+1, $mday, + $hour, $min, $sec); +} + +sub mail_notification { + local($name, @text) = @_; + open(MAIL, "| $MAILER -s \"CVS Update: " . $modulename . "\" " . $name); + print MAIL join("\n", @text), "\n"; + close(MAIL); +} + +sub write_commitlog { + local($logfile, @text) = @_; + + open(FILE, ">>$logfile"); + print FILE join("\n", @text), "\n"; + close(FILE); +} + +# +# Main Body +# + +# Initialize basic variables +# +$debug = 0; +$id = getpgrp(); # note, you *must* use a shell which does setpgrp() +$state = $STATE_NONE; +$login = getlogin || (getpwuid($<))[0] || "nobody"; +chop($hostname = `hostname`); +chop($domainname = `domainname`); +$hostdomain = $hostname . $domainname; +$cvsroot = $ENV{'CVSROOT'}; +$do_status = 1; +$modulename = ""; + +# parse command line arguments (file list is seen as one arg) +# +while (@ARGV) { + $arg = shift @ARGV; + + if ($arg eq '-d') { + $debug = 1; + print STDERR "Debug turned on...\n"; + } elsif ($arg eq '-m') { + $mailto = "$mailto " . shift @ARGV; + } elsif ($arg eq '-M') { + $modulename = shift @ARGV; + } elsif ($arg eq '-s') { + $do_status = 0; + } elsif ($arg eq '-f') { + ($commitlog) && die("Too many '-f' args\n"); + $commitlog = shift @ARGV; + } else { + ($donefiles) && die("Too many arguments! Check usage.\n"); + $donefiles = 1; + @files = split(/ /, $arg); + } +} +($mailto) || die("No -m mail recipient specified\n"); + +# for now, the first "file" is the repository directory being committed, +# relative to the $CVSROOT location +# +@path = split('/', $files[0]); + +# XXX there are some ugly assumptions in here about module names and +# XXX directories relative to the $CVSROOT location -- really should +# XXX read $CVSROOT/CVSROOT/modules, but that's not so easy to do, since +# XXX we have to parse it backwards. +# +if ($modulename eq "") { + $modulename = $path[0]; # I.e. the module name == top-level dir +} +if ($#path == 0) { + $dir = "."; +} else { + $dir = join('/', @path); +} +$dir = $dir . "/"; + +if ($debug) { + print STDERR "module - ", $modulename, "\n"; + print STDERR "dir - ", $dir, "\n"; + print STDERR "path - ", join(":", @path), "\n"; + print STDERR "files - ", join(":", @files), "\n"; + print STDERR "id - ", $id, "\n"; +} + +# Check for a new directory first. This appears with files set as follows: +# +# files[0] - "path/name/newdir" +# files[1] - "-" +# files[2] - "New" +# files[3] - "directory" +# +if ($files[2] =~ /New/ && $files[3] =~ /directory/) { + local(@text); + + @text = (); + push(@text, &build_header()); + push(@text, ""); + push(@text, $files[0]); + push(@text, ""); + + while (<STDIN>) { + chop; # Drop the newline + push(@text, $_); + } + + &mail_notification($mailto, @text); + + exit 0; +} + +# Check for an import command. This appears with files set as follows: +# +# files[0] - "path/name" +# files[1] - "-" +# files[2] - "Imported" +# files[3] - "sources" +# +if ($files[2] =~ /Imported/ && $files[3] =~ /sources/) { + local(@text); + + @text = (); + push(@text, &build_header()); + push(@text, ""); + push(@text, $files[0]); + push(@text, ""); + + while (<STDIN>) { + chop; # Drop the newline + push(@text, $_); + } + + &mail_notification($mailto, @text); + + exit 0; +} + +# Iterate over the body of the message collecting information. +# +while (<STDIN>) { + chop; # Drop the newline + + if (/^In directory/) { + push(@log_lines, $_); + push(@log_lines, ""); + next; + } + + 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 whitespace + s/[ \t\n]+$//; # delete trailing whitespace + + if ($state == $STATE_CHANGED) { push(@changed_files, split); } + if ($state == $STATE_ADDED) { push(@added_files, split); } + if ($state == $STATE_REMOVED) { push(@removed_files, split); } + if ($state == $STATE_LOG) { push(@log_lines, $_); } +} + +# 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); + } +} + +if ($debug) { + print STDERR "Searching for log file index..."; +} +# Find an index to a log file that matches this log message +# +for ($i = 0; ; $i++) { + local(@text); + + last if (! -e "$LOG_FILE.$i.$id"); # the next available one + @text = &read_logfile("$LOG_FILE.$i.$id", ""); + last if ($#text == -1); # nothing in this file, use it + last if (join(" ", @log_lines) eq join(" ", @text)); # it's the same log message as another +} +if ($debug) { + print STDERR " found log file at $i.$id, now writing tmp files.\n"; +} + +# Spit out the information gathered in this pass. +# +&append_names_to_file("$CHANGED_FILE.$i.$id", $dir, @changed_files); +&append_names_to_file("$ADDED_FILE.$i.$id", $dir, @added_files); +&append_names_to_file("$REMOVED_FILE.$i.$id", $dir, @removed_files); +&write_logfile("$LOG_FILE.$i.$id", @log_lines); + +# Check whether this is the last directory. If not, quit. +# +if ($debug) { + print STDERR "Checking current dir against last dir.\n"; +} +$_ = &read_line("$LAST_FILE.$id"); + +if ($_ ne $cvsroot . "/" . $files[0]) { + if ($debug) { + print STDERR sprintf("Current directory %s is not last directory %s.\n", $cvsroot . "/" .$files[0], $_); + } + exit 0; +} +if ($debug) { + print STDERR sprintf("Current directory %s is last directory %s -- all commits done.\n", $files[0], $_); +} + +# +# End Of Commits! +# + +# 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. +# + +# +# Produce the final compilation of the log messages +# +@text = (); +@status_txt = (); +push(@text, &build_header()); +push(@text, ""); + +for ($i = 0; ; $i++) { + last if (! -e "$LOG_FILE.$i.$id"); # we're done them all! + @lines = &read_logfile("$CHANGED_FILE.$i.$id", ""); + if ($#lines >= 0) { + push(@text, "Modified files:"); + push(@text, &format_lists(@lines)); + } + @lines = &read_logfile("$ADDED_FILE.$i.$id", ""); + if ($#lines >= 0) { + push(@text, "Added files:"); + push(@text, &format_lists(@lines)); + } + @lines = &read_logfile("$REMOVED_FILE.$i.$id", ""); + if ($#lines >= 0) { + push(@text, "Removed files:"); + push(@text, &format_lists(@lines)); + } + if ($#text >= 0) { + push(@text, ""); + } + @lines = &read_logfile("$LOG_FILE.$i.$id", "\t"); + if ($#lines >= 0) { + push(@text, "Log message:"); + push(@text, @lines); + push(@text, ""); + } + if ($do_status) { + local(@changed_files); + + @changed_files = (); + push(@changed_files, &read_logfile("$CHANGED_FILE.$i.$id", "")); + push(@changed_files, &read_logfile("$ADDED_FILE.$i.$id", "")); + push(@changed_files, &read_logfile("$REMOVED_FILE.$i.$id", "")); + + if ($debug) { + print STDERR "main: pre-sort changed_files = ", join(":", @changed_files), ".\n"; + } + sort(@changed_files); + if ($debug) { + print STDERR "main: post-sort changed_files = ", join(":", @changed_files), ".\n"; + } + + foreach $dofile (@changed_files) { + if ($dofile =~ /\/$/) { + next; # ignore the silly "dir" entries + } + if ($debug) { + print STDERR "main(): doing status on $dofile\n"; + } + open(STATUS, "-|") || exec 'cvs', '-n', 'status', '-Qqv', $dofile; + while (<STATUS>) { + chop; + push(@status_txt, $_); + } + } + } +} + +# Write to the commitlog file +# +if ($commitlog) { + &write_commitlog($commitlog, @text); +} + +if ($#status_txt >= 0) { + push(@text, @status_txt); +} + +# Mailout the notification. +# +&mail_notification($mailto, @text); + +# cleanup +# +if (! $debug) { + &cleanup_tmpfiles(); +} + +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 00000000000..622fe98a82b --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/mfpipe.pl @@ -0,0 +1,88 @@ +#! xPERL_PATHx +# -*-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. +# +# $Id: mfpipe.pl,v 1.1 1995/12/19 09:21:40 deraadt 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 00000000000..1d6483d54fe --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/ChangeLog @@ -0,0 +1,766 @@ +Sun Jul 9 20:57:11 1995 Karl Fogel <kfogel@floss.cyclic.com> + + * "/bin/rmdir" as default, not "/usr/local/bin/rmdir". + +Fri Jun 16 15:24:34 1995 Jim Kingdon (kingdon@cyclic.com) + + * pcl-cvs.elc, pcl-cvs-lucid.elc: Added. + + * Makefile.in: Rename from Makefile and set srcdir. + +Thu May 18 17:10:27 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> + + Automatically guess CVS log entries from ChangeLog contents. + * pcl-cvs.el (cvs-mode-changelog-commit): New command. + (cvs-changelog-full-paragraphs): New variable. + (cvs-changelog-name, cvs-narrow-changelog, + cvs-changelog-paragraph, cvs-changelog-subparagraph, + cvs-changelog-entry, cvs-changelog-ours-p, cvs-relative-path, + cvs-changelog-entries, cvs-changelog-insert-entries, cvs-union, + cvs-insert-changelog-entries, cvs-edit-delete-common-indentation): + New functions. + (cvs-mode-map): Bind 'C' to cvs-mode-changelog-commit. + (cvs-mode): Mention cvs-mode-changelog-commit in docstring. + + Give the info files names ending in ".info". + * Makefile (INFOFILES, install_info): Change pcl-cvs to + pcl-cvs.info. + (pcl-cvs.info): Target renamed from pcl-cvs. + (DISTFILES): pcl-cvs removed; we handle the info files explicitly + in the dist-dir target. + (dist-dir): Depend on pcl-cvs.info. Distribute pcl-cvs.info*. + * pcl-cvs.texinfo: Change @setfilename appropriately. + * INSTALL: Updated. + * .cvsignore: Correctly ignore the info files. + + * README: Note that pcl-cvs has been tested under 19.28, and that + the "cookie" naming conflict was resolved in 19.11. + + * Makefile (pcl-cvs-lucid.elc): Changed this target from + pcl-cvs-lucid.el. That's a source file, for goodness' sake! + +Tue May 9 13:56:50 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> + + * Change references to "Cygnus's remote CVS" to "Cyclic CVS". + +Wed May 3 13:55:27 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> + + * pcl-cvs.el (cvs-parse-stderr): Handle colons after both + "rcsmerge" and "warning". + +Fri Apr 28 22:38:14 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> + + * Makefile (ELFILES): Include pcl-cvs-startup.el. + (info, pcl-cvs): Call makeinfo appropriately for modern versions. + (pcl-cvs.aux): List dependency on pcl-cvs.texinfo. + (pcl-cvs.ps): New target. + (DVIPS): New variable. + (dist-dir): Renamed from dist, updated to accept DISTDIR value + passed from parent. + (DISTFILES): New varible. + (pcl-cvs.elc, pcl-cvs-lucid.elc): Add targets to elcfiles target. + +Tue Apr 25 21:33:49 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> + + * pcl-cvs.el: (cvs-parse-stderr): Recognize "conflicts" as well as + "overlaps" before "during merge." + +Thu Feb 16 12:17:20 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> + + * pcl-cvs.el (cvs-parse-stderr): Recognize "conflicts found in..." + messages attributed to "cvs server", as well as "cvs update". + +Sat Feb 4 01:47:01 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> + + * pcl-cvs.el: Deal with the 'P' action, produced by remote CVS. + (cvs-parse-stdout): Treat 'P' like 'U' --- file is updated. + +Tue Jan 31 23:31:39 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> + + * pcl-cvs.el (cvs-cvsroot-required): New variable. + (cvs-do-update): If cvs-cvsroot-required is not set, don't complain if + CVSROOT and cvs-cvsroot are both unset. + +Sun Jan 22 21:22:22 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> + + * pcl-cvs.el (cvs-parse-stderr): + Some changes for Cygnus's Remote CVS. Treat + messages like "cvs server: Updating DIRECTORY" as we treat those like + "cvs update: Updating DIRECTORY". Ignore other messages starting with + "cvs server". + + * pcl-cvs.el (cvs-parse-stderr): Re-indent. + + * .cvsignore: Add ignore list for Texinfo litter. + + * Makefile (lispdir): Set appropriately for totoro. + * pcl-cvs.el (cvs-program, cvs-diff-program, cvs-rmdir-program): Same. + +Tue Jun 1 00:00:03 1993 Per Cederqvist (ceder@lysator.liu.se) + + * Release 1.05. (This release was promised before the end of May, + but I didn't quite make it. No, I didn't fake the date above). + +Mon May 31 01:32:25 1993 Per Cederqvist (ceder@lysator.liu.se) + + * Removed the elib sub-directory. Users must now get the Elib + library separately. + * pcl-cvs.texinfo: Document it. + + * pcl-cvs-lucid.el: A new version, supplied by Jamie Zawinsky, + added. + + * pcl-cvs Id 68: Transform RCS keywords + * Makefile (pcl-cvs-$(VER)): Remove the $ signs in most files in + the distribution. + + * pcl-cvs Id 76: Extra " in cvs-mode-add. + * pcl-cvs.el (cvs-mode-add): Don't add the extra level of quotes + around the log message, since it doesn't work with CVS. + + * pcl-cvs Id 56: '-d <CVSROOT>' support in pcl-cvs + * pcl-cvs.el (cvs-change-cvsroot): New function. + + * pcl-cvs Id 77: *cvs* isn't cleared properly + * pcl-cvs.el (cvs-do-update): Always erase the *cvs* buffer and + re-create the collection. + + * pcl-cvs.el (cvs-do-update): Set mode-line-process in the *cvs* + buffer. + * pcl-cvs.el (cvs-mode): Reset mode-line-process. + + * pcl-cvs Id 59: sort .cvsignore alphabetically! + * pcl-cvs.el (cvs-sort-ignore-file): New variable. + * pcl-cvs.el (cvs-mode-ignore): Use it. + * pcl-cvs.texinfo: Document it. + + * pcl-cvs Id 75: Require final newline. + * pcl-cvs.el (cvs-commit-buffer-require-final-newline): New + variable. + * pcl-cvs.el (cvs-edit-done): Use it. + * pcl-cvs.texinfo: Document it. + + * pcl-cvs Id 72: make clean deletes lucid-emacs.el + * dist-makefile (ELCFILES): Fixed a typo. + + * pcl-cvs Id 46: "cvs remove f" "touch f" "cvs update f" -> parse err. + * pcl-cvs.el (cvs-fileinfo->type): New type: REM-EXIST. + * pcl-cvs.el (cvs-shadow-entry-p): A REMOVED that follows a + REM-EXIST is a shadow. + * pcl-cvs.el (cvs-parse-stderr): Recognize the "should be removed + and is still there" message. + * pcl-cvs.el (cvs-pp): Recognize REM-EXIST. + * pcl-cvs.el (cvs-mode-undo-local-changes): Recognize and complain + about REM-EXIST. Defensive test added: complain about unknown types. + + * pcl-cvs.el (cvs-mode-add): Add an extra level of quotes around + the log message. This is apparently needed by RCVS. <This change + has been removed. --ceder>. + + * pcl-cvs.el (cvs-parse-stderr): Ignore output from RCVS. + +Tue Apr 27 00:48:40 1993 Per Cederqvist (ceder@lysator.liu.se) + + * pcl-cvs.el (cvs-startup-message): Now a defconst instead of a + defvar. + * pcl-cvs.el (cvs-mode-commit): Add a defvar for it. + + * dist-makefile (EMACS): Use $(EMACS) instead of hard-coding 'emacs'. + +Sat Apr 17 12:47:10 1993 Per Cederqvist (ceder@lysator.liu.se) + + * Release 1.04. + + * pcl-cvs.texinfo: Updated the Contributors node. + + * pcl-cvs Id 58: Lucid GNU Emacs support + * pcl-cvs-lucid.el: New file, contributed by the people at Lucid. + * pcl-cvs.el: Autoload pcl-cvs-lucid if running in an Lucid GNU + Emacs. + * compile-all.el: (files-to-compile): Add pcl-cvs-lucid. + * dist-makefile (ELFILES, ELCFILES): Dito. + + * pcl-cvs Id 55: cvs-diff-backup swaps old and new version. + * pcl-cvs.el (cvs-diff-backup-extractor): Old version should be + first. + * pcl-cvs.el (cvs-mode-diff-backup): Call cvs-backup-diffable + correctly. + + * pcl-cvs Id 64: elib substitute + * dist-makefile (install): Warn about Elib. + * pcl-cvs.texinfo: Talk about Elib. + + * pcl-cvs Id 50: Committing the *commit* buffer twice. + * pcl-cvs.el (cvs-edit-done): Report an error if cvs-commit-list + is empty, and empty it when the commit is done. + + * pcl-cvs Id 56: '-d <CVSROOT>' support. + * pcl-cvs.el (cvs-cvsroot): New variable. + * pcl-cvs.el (cvs-do-update, all callers of cvs-execute-list): Use + it everywhere CVS is called, to override CVSROOT. + * pcl-cvs.texinfo (Customization): Document it. + +Thu Apr 1 00:34:55 1993 Per Cederqvist (ceder@lysator.liu.se) + + * pcl-cvs.el (cvs-retrieve-revision-to-tmpfile): Exit status nil + from call-process means everything was successful in some Emacs + versions. + + * pcl-cvs.el (cvs-mode-map): Bind "q" to bury-buffer. + * pcl-cvs.texinfo: Document it. + +Thu Mar 11 00:05:03 1993 Per Cederqvist (ceder@lysator.liu.se) + + * Release 1.03-Emerge (not released). + + * Makefile (pcl-cvs-$(VER)): Don't includ elib-dll-debug.el in the + distribution. (It's included as elib/dll-debug.el). + + * pcl-cvs.el (cvs-mode): Document the "e" key (cvs-mode-emerge). + +Tue Mar 9 00:02:57 1993 Per Cederqvist (ceder@lysator.liu.se) + + * pcl-cvs.texinfo (Emerge): New node. + + * pcl-cvs.el (cvs-kill-buffer-visiting): New function. + + * pcl-cvs.el (cvs-mode-emerge): Handle Conflict and Merged files. + + * pcl-cvs.el (cvs-retrieve-revision-to-tmpfile): Handle any revision. + + * pcl-cvs.el (cvs-fileinfo-*): Store base-revision instead of + backup-file. + + * pcl-cvs.el (cvs-backup-diffable): The file is only diffable if + the backup file is readable. + + * pcl-cvs.el (cvs-mode-map): Bind "e" to cvs-mode-emerge instead + of cvs-mode-find-file (which is anyhow bound to "f"). + +Mon Mar 8 23:06:52 1993 Per Cederqvist (ceder@lysator.liu.se) + + * pcl-cvs.el (cvs-mode-emerge): New function. Currently only + handles emerge of Modified files. + + * pcl-cvs.el (cvs-retrieve-revision-to-tmpfile): New function. + +Sun Jan 24 20:07:18 1993 Per Cederqvist (ceder@lysator.liu.se) + + * elib-dll-debug.el: Moved to elib. + +Mon Jan 18 00:35:59 1993 Per Cederqvist (ceder@mauritz) + + * pcl-cvs.el (cvs-do-update): Added a probably unnecessary sit-for. + + * Release 1.03-Elib-0.05.1 (not released). + + * Elib 0.05 compatibility: + * elib-dll-debug.el, pcl-cvs-buffer.el, test-dll.el: Fix the + require strings. + * pcl-cvs.el (cvs-pp): Insert the string. + + * Release 1.03-Elib-0.05 (not released). + + * elib: New directory, containing the parts of elib that are + required for pcl-cvs. Changes to the files in that directory + that are present in Elib are documented in the ChangeLog of + Elib, not here. + * Makefile (pcl-cvs-$(VER)): Copy the new dir to the distribution. + * dist-makefile (ELFILES, ELCFILES): Don't include the Elib files. + +Fri Jan 8 02:43:49 1993 Per Cederqvist (ceder@konrad) + + * pcl-cvs.el (cvs-mode-map): Bind "e" to cvs-mode-find-file, like + in dired. + +Sun Jan 3 23:25:13 1993 Per Cederqvist (ceder@konrad) + + * elib-dll.el, elib-node.el, cookie.el: Moved to the elib package. + Pcl-cvs now requires elib. + +Tue Dec 29 22:06:57 1992 Per Cederqvist (ceder@konrad) + + * pcl-cvs.el: Tracked the latest (last?) rename of all functions + in cookie.el. + +Thu Sep 24 00:29:16 1992 Per Cederqvist (ceder@robert) + + * pcl-cvs.texinfo (Archives): This version is not distributed with + CVS 1.3, so don't claim that it is. + +Fri Aug 21 15:17:08 1992 Per Cederqvist (ceder@maskros) + + * pcl-cvs.el (cvs-parse-stderr): Fixed two "(set head" that should + be "(setq head". + +Thu Aug 20 05:53:58 1992 Per Cederqvist (ceder@robin) + + * cookie.el: Changes to this file is documented in the ChangeLog + of elib in the future. + +Tue Aug 18 03:30:28 1992 Per Cederqvist (ceder@robin) + + * pcl-cvs.el: Don't use cookie-last-tin (which no longer exists). + + * cookie.el: Use prefix cookie:: for internal functions. + + * cookie.el: (cookie:enter-after, cookie:enter-before, + cookie:nth-cookie): Implemented. + * cookie.el: No longer define (impl). + + * cookie.el: More renames: + cookie:next-cookie -> cookie:goto-next-tin + cookie:previous-cookie -> cookie:goto-previous-tin + tin-next -> cookie:next-tin + tin-previous -> cookie:previous-tin + tin-nth -> cookie:nth-tin + tin-delete -> cookie:delete-tin + cookie:collect -> cookie:collect-cookies + cookie:tin-collect -> cookie:collect-tins + (new) -> cookie:tin-collect-cookies + (new) -> cookie:tin-collect-tins + cookie:refresh -> cookie:refresh-all + tin-invalidate-tins -> cookie:invalidate-tins + +Mon Aug 17 01:39:49 1992 Per Cederqvist (ceder@robin) + + * cookie.el (cookie:set-buffer-bind-dll-let*): New macro. Used in + many places instead of cookie:set-buffer-bind-dll. + * cookie.el (cookie:set-buffer-bind-dll): Renamed the macro + cookie:set-buffer to this. + + * pcl-cvs.el (cvs-use-temp-buffer): Set default-directory. + +Sun Aug 16 20:51:30 1992 Per Cederqvist (ceder@robin) + + * pcl-cvs.el (cvs-add-sub): Fixed call to cvs-add-file-update-buffer. + +Sat Aug 8 20:28:21 1992 Per Cederqvist (ceder@robin) + + * Release 1.03-Cookie-II (not released). + + * pcl-cvs.el (cvs-mode-diff-cvs): Don't care about the exit status + from ``cvs diff''. + + * pcl-cvs.el (cvs-mode): Document cvs-mode-undo-local-changes. + * pcl-cvs.el (cvs-diffable): New function. + + * pcl-cvs.el: Use the new cookie package. + * pcl-cvs.el (cvs-cookie-handle): New variable. + * pcl-cvs.el (cvs-do-update): User the new cookie:create + interface, and cookie:clear if the buffer already existed. Make + the buffer read-only. + * pcl-cvs.el (cvs-mode-next-line, cvs-mode-previous-line): New + functions (used instead of cookie:next-cookie and + cookie:previous-cookie). + + * cookie.el: Major redesign. The handle that is passed to all + cookie functions is now a new datatype, and not the buffer that + the cookies resides in. This way it is possible to have more than + one set of cookies in a buffer. Things that used to be + buffer-local variables are now fields in the handle data type. + cookie-last-tin is no longer available. + * cookie.el (cookie:create): The buffer is not cleared, nor set to + be read-only. + * cookie.el (cookie:next-cookie, cookie:previous-cookie): Since + the first argument is now a handle and not a buffer, these can no + longer be called interactively. You have to write a small wrapper + about them. + * cookie.el (cookie:buffer): New function. + +Tue Aug 4 03:02:25 1992 Per Cederqvist (ceder@robert) + + * pcl-cvs.texinfo (Bugs): Renamed "Reporting bugs and ideas" to + "Bugs" and added a table of known bugs/FAQ:s. + +Mon Aug 3 00:19:39 1992 Per Cederqvist (ceder@robert) + + * pcl-cvs.el, pcl-cvs.texinfo: Big Renaming Time! + The commands that operate in the *cvs* buffer: + cvs-add-change-log-entry-other-window -> cvs-mode-add-change-log-entry-other-window + cvs-mark-all-files -> cvs-mode-mark-all-files + cvs-revert-updated-buffers -> cvs-mode-revert-updated-buffers + cvs-undo-local-changes -> cvs-mode-undo-local-changes + cvs-unmark-up -> cvs-mode-unmark-up + cvs-acknowledge -> cvs-mode-acknowledge + cvs-unmark-all-files -> cvs-mode-unmark-all-files + cvs-add -> cvs-mode-add + cvs-diff-backup -> cvs-mode-diff-backup + cvs-commit -> cvs-mode-commit + cvs-diff-cvs -> cvs-mode-diff-cvs + cvs-find-file -> cvs-mode-find-file + cvs-update-no-prompt -> cvs-mode-update-no-prompt + cvs-ignore -> cvs-mode-ignore + cvs-log -> cvs-mode-log + cvs-mark -> cvs-mode-mark + cvs-find-file-other-window -> cvs-mode-find-file-other-window + cvs-remove-file -> cvs-mode-remove-file + cvs-status -> cvs-mode-status + cvs-remove-handled -> cvs-mode-remove-handled + cvs-unmark -> cvs-mode-unmark + + * pcl-cvs.el (cvs-cvs-diff-flags): Variable deleted. + * pcl-cvs.el (cvs-diff-cvs): Use cvs-diff-flags instead. + * pcl-cvs.texinfo (Customization): Update the doc. + + * pcl-cvs.el (cvs-diff-cvs): Handle exit status 0 (no diffs), 1 + (diffs) and other (error). + * pcl-cvs.el (cvs-execute-list): Add support for this kind of + thing. + + * Revert buffers for committed files: + * pcl-cvs.el (cvs-auto-revert-after-commit): New variable. + * pcl-cvs.texinfo (Committing changes, Customization): Document + it. + * pcl-cvs.el (cvs-after-commit-function): New function. + + * pcl-cvs.el (cvs-execute-list): Return the exit status or nil. + * pcl-cvs.el (cvs-edit-done, cvs-diff-cvs, cvs-remove-file, + cvs-undo-local-changes, cvs-add, cvs-status, cvs-log): Use the + exit status to generate an error message. + + + * pcl-cvs.el (cvs-do-update): It should be "cvs -n update -l", not + "cvs -l update -n". Put the -n and/or -l in the message that is + displayed in the *cvs* buffer during the update. + +Sat Aug 1 00:55:49 1992 Per Cederqvist (ceder@robert) + + * cookie.el (cookie-sort): New function. + + * cookie.el (cookie-clear): Rewritten. No longer clears all local + variables. + +Tue Jul 28 17:21:17 1992 Per Cederqvist (ceder@robin) + + * pcl-cvs.el (cvs-parse-stderr): Try to handle the output from RCS + when it is compiled without DIFF3_BIN and a conflict occurs. + + * pcl-cvs.texinfo (Getting Started): Fixed typo. + + * pcl-cvs-startup.el (cvs-update-other-window): Make the autoload + be interactive. + +Mon Jul 27 19:36:40 1992 Per Cederqvist (ceder@robin) + + * pcl-cvs.el (cvs-revert-updated-buffers, cvs-revert-fileinfo): + New functions. + * pcl-cvs.texinfo (Reverting your buffers): Document it. + + * pcl-cvs.el (cvs-fileinfo->full-path): New function. + * pcl-cvs.el (cvs-full-path): Use it. + + * cookie.el (cookie-map, cookie-map-reverse): Better doc- + string. Removed the unused local variable 'result'. + + * compile-all.el: Renamed elib-files to files-to-compare. + * compile-all.el (compile-pcl-cvs): Bind load-path in a let + statement instead of globally. + +Thu Jul 23 19:02:41 1992 Per Cederqvist (ceder@robin) + + * pcl-cvs.el (cvs-do-update): Check that CVSROOT is set. + * pcl-cvs.el (cvs-diff-cvs): Check that cvs-cvs-diff-flags is a + list. + * pcl-cvs.el (cvs-diff-backup): Check that cvs-diff-flags is a + list. + +Tue Jul 21 11:27:39 1992 Per Cederqvist (ceder@robin) + + * pcl-cvs.el (cvs-parse-error): Make the *cvs* buffer writeable + before trying to write the email message. Require sendmail before + trying to switch to mail-mode. + + * pcl-cvs.el (cvs-do-update): Check that cvs-program exists. + + * pcl-cvs.el (cvs-skip-line): Fixed bracketing error. + +Mon Jul 20 10:31:51 1992 Per Cederqvist (ceder@robin) + + * Release 1.03. + + * pcl-cvs.el, cookie.el: Indentation fixes. + + * Makefile (pcl-cvs-$(VER)): Include NEWS in the distribution. + + * pcl-cvs.el (cvs-rm-program): Deleted. + * pcl-cvs.el (cvs-rmdir-program, cvs-lock-file): New variables. + + * Handle lock files in a nicer way: + * pcl-cvs.el (cvs-update-filter, cvs-delete-lock, + cvs-lock-file-p): New functions. + * pcl-cvs.el (cvs-do-update, cvs-sentinel): Redirect stdout to the + temporary file, not stderr. Use cvs-update-filter. + * pcl-cvs.el (cvs-parse-update): New arguments. + * pcl-cvs.el (cvs-parse-buffer): Renamed to cvs-parse-update. + * pcl-cvs.el (cvs-stderr-file): Renamed to cvs-stdout-file. + * pcl-cvs.texinfo (Miscellaneous commands, Updating the + directory): Document cvs-delete-lock. + + * pcl-cvs.el (cvs-mode): Don't reset buffer-read-only. + + * pcl-cvs.el (cvs-find-file-other-window): Don't save-some-buffers. + +Thu Jul 16 00:19:58 1992 Per Cederqvist (ceder@robin) + + * pcl-cvs.el, test-cookie-el: Use the new names from cookie.el. + + * cookie.el: Big Renaming Time! + External functions: + cookie-next -> tin-next + cookie-previous -> tin-previous + cookie-nth -> tin-nth + cookie-delete -> tin-delete + cookie-filter-tins -> tin-filter + cookie-get-selection -> tin-get-selection + cookie-start-marker -> tin-start-marker + cookie-end-marker -> tin-end-marker + cookie-invalidate-tins -> tin-invalidate-tins + cookie-collect-tins -> tin-collect + cookie-collect-cookies -> cookie-collect + Internal functions: + cookie-create-tin -> cookie-create-wrapper + cookie-tin-start-marker -> cookie-wrapper-start-marker + cookie-tin-cookie-safe -> cookie-wrapper-cookie-safe + cookie-tin-cookie -> cookie-wrapper-cookie + set-cookie-tin-start-marker -> cookie-wrapper-set-start-marker + set-cookie-tin-cookie -> cookie-wrapper-set-cookie + cookie-tin-p -> cookie-wrapper-p + cookie-create-tin-and-insert -> cookie-create-wrapper-and-insert + + * pcl-cvs.el (cvs-find-file, cvs-find-file-other-window): Signal + an appropriate error message if the *cvs* buffer is empty. + + * cookie.el (cookie-create): Make the buffer read-only. + * cookie.el (cookie-create-tin-and-insert, cookie-refresh, + cookie-delete-tin-internal, cookie-refresh-tin): Bind + buffer-read-only to nil while changing the contents of + the buffer. + + * pcl-cvs.el (cvs-byte-compile-files): New function. + * pcl-cvs.texinfo (Miscellaneous commands): Document it. + + * pcl-cvs.el (cvs-diff-ignore-marks): New variable. + * pcl-cvs.el (cvs-diff-cvs, cvs-diff-backup): Don't consider + marked files to be selected if a prefix argument is given XOR the + variable cvs-diff-ignore-marks is non-nil. + * pcl-cvs.el (cvs-get-marked): New optional argument `ignore-marks'. + * pcl-cvs.texinfo (Customization, Viewing differences): Document + this behaviour. + + * pcl-cvs.el (cvs-undo-local-changes): New function. + * pcl-cvs.texinfo (Undoing changes): Document + cvs-undo-local-changes. + * pcl-cvs.el (cvs-mode-map): cvs-unmark-all-files moved from "U" + to "ESC DEL". cvs-undo-local-changes bound to "U". + * pcl-cvs.texinfo (Marking files): Document ESC DEL. + + * pcl-cvs.el (cvs-skip-line): New arguments. All callers updated. + Now calls cvs-parse-error if a parse error occurs. + * pcl-cvs.el (cvs-parse-error): New function that creates a bug + report. + * pcl-cvs.el (cvs-parse-stderr, cvs-parse-stdout): New arguments. + The only caller (cvs-parse-buffer) updated. Call cvs-parse-error + in case of parse error. + + * pcl-cvs.el (pcl-cvs-version): New variable. + + * cookie.el (cookie-create): Kill all local variables in the buffer. + +Fri Jul 10 11:17:40 1992 Per Cederqvist (ceder@robin) + + * Release 1.03beta1. + +Thu Jul 9 03:12:00 1992 Per Cederqvist (ceder@robin) + + * pcl-cvs.el (cvs-update-running): New variable. + * pcl-cvs.el (cvs-do-update): Use it instead of the previous local + variable cvs-process (that no longer exists). Make sure that only + one `cvs update' runs at any given moment. + * pcl-cvs.el (cvs-sentinel): Reset cvs-update-running when the + update process exits. + + * pcl-cvs.el (cvs-update): Switch to the *cvs* buffer. + * pcl-cvs.el (cvs-update-other-window): New function. + * pcl-cvs-startup.el (cvs-update-other-window): Added a autoload + for it. + * pcl-cvs.el (cvs-do-update): Don't pop up any buffer in a window + - let cvs-update or cvs-update-other-window handle that. Also + don't kill the *cvs* buffer, but rather insert a "Running cvs..." + message into it. + * pcl-cvs.el (cvs-parse-buffer): Don't change the window + configuration. + + * pcl-cvs.el (cvs-create-fileinfo, cvs-pp, cvs-fileninfo->type): + New type for a fileinfo: MESSAGE. + + * pcl-cvs.el (cvs-cvs-buffer): Deleted the variable. Use + cvs-buffer-name instead. (I no longer have any plans to allow more + than one cvs update to run at the same time - things only get + confusing). Changed all places where cvs-cvs-buffer was used. + + * pcl-cvs.el: Take care of update programs (the -u option in the + modules file): + * pcl-cvs.el (cvs-update-prog-output-skip-regexp): New variable. + * pcl-cvs.el (cvs-parse-stdout): Skip output from the update + program (using cvs-update-prog-output-skip-regexp). + * pcl-cvs.texinfo (Future enhancements): Document that the + solution is not as good as it should be. + * pcl-cvs.texinfo (Customization): Document the variable. + +Wed Jul 8 20:29:44 1992 Per Cederqvist (ceder@robin) + + * pcl-cvs.el (cvs-do-update): Check that this-dir really exists + and is a directory, and that this-dir/CVS exists and is a + directory. + +Tue Jul 7 01:02:24 1992 Per Cederqvist (ceder@robin) + + * pcl-cvs.texinfo (Customization): Document TMPDIR. + + * This chunk of modifications should make it possible to run + pcl-cvs on hosts that do not line-buffer stdout (such as + DECstation). They work by diverting stdout and stderr from + `cvs update' and later sorting them together. + * pcl-cvs.el (cvs-parse-stderr): Don't fail to parse conflict + data. + * pcl-cvs.el (cvs-remove-stdout-shadows, cvs-shadow-entry-p): New + functions. + * pcl-cvs.el (cvs-parse-buffer): Use it. + * pcl-cvs.el (cvs-remove-empty-directories): New function. + * pcl-cvs.el (cvs-remove-handled, cvs-parse-buffer): Use it. + * pcl-cvs.el (cvs-get-current-dir): New argument ROOT-DIR. All + calls to cvs-get-current-dir updated. + * pcl-cvs.el (cvs-do-update): Allocate a tmp file. Use cvs-shell + (typically /bin/sh) to redirect stderr from CVS to the tmp file. + * pcl-cvs.el (cvs-sentinel): Handle the tmp file. Remove it when + it is parsed. + * pcl-cvs.el (cvs-parse-buffer): New argument STDERR-BUFFER. All + calls to cvs-parse-buffer updated. Rewritten to handle the + separation of stderr and stdout. + * pcl-cvs.el (cvs-shell, cvs-stderr-file): New variables. + * pcl-cvs.el (cvs-compare-fileinfos, cvs-parse-stderr, + cvs-parse-stdout): New functions. + + * pcl-cvs.el (cvs-parse-buffer): Some modifications for output + from RCS 5.6. + +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 00000000000..76799679ac5 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/INSTALL @@ -0,0 +1,89 @@ +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. Release 1.05 and later of pcl-cvs requires parts of the Elib + library, version 0.07 or later. Elib is available via anonymous + ftp from prep.ai.mit.edu in `pub/gnu/elib-0.07.tar.z', and from + a lot of other sites that mirrors prep. Get Elib, and install + it, before proceeding. + + 4. 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. + + 5. 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. Move the info file `pcl-cvs.info' to your standard info + directory. This might be called something like + `/usr/gnu/emacs/info'. + + 2. Edit the file `dir' in the info directory and enter one line to + contain a pointer to the info file `pcl-cvs.info'. The line can, + for instance, look like this: + + * Pcl-cvs: (pcl-cvs.info). An Emacs front-end to CVS. + + +How to make the on-line manual from pcl-cvs.texinfo +=================================================== + + 1. Create the info file `pcl-cvs.info' 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). + + +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.in b/gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile.in new file mode 100644 index 00000000000..a96f626e593 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile.in @@ -0,0 +1,109 @@ +# @(#) Id: dist-makefile,v 1.19 1993/05/31 22:43:45 ceder Exp +# Makefile for pcl-cvs release 1.05. +# Copyright (C) 1992, 1993 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/emacs/site-lisp/pcl-cvs + +# Where to install the info file. + +prefix=/usr/local +infodir = $(prefix)/info + +# Used to byte-compile files. + +EMACS=emacs + +# +# The rest of this file should not need to be modified. +# + +srcdir = @srcdir@ +VPATH = @srcdir@ + +# Just in case... +SHELL = /bin/sh + +ELFILES = pcl-cvs.el pcl-cvs-lucid.el pcl-cvs-startup.el +ELCFILES = pcl-cvs.elc pcl-cvs-lucid.elc +INFOFILES = pcl-cvs.info* +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) + +pcl-cvs.elc pcl-cvs-lucid.elc elcfiles: + $(EMACS) -batch -l ${srcdir}/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.info + $(INSTALL_DATA) pcl-cvs.info* $(infodir)/pcl-cvs.info + +info pcl-cvs.info: pcl-cvs.texinfo + makeinfo --fill-column=70 ${srcdir}/pcl-cvs.texinfo + +pcl-cvs.aux pcl-cvs.dvi: pcl-cvs.texinfo + tex ${srcdir}/pcl-cvs.texinfo + tex ${srcdir}/pcl-cvs.texinfo + -texindex pcl-cvs.cp pcl-cvs.fn pcl-cvs.vr pcl-cvs.tp pcl-cvs.ky \ + pcl-cvs.pg + tex ${srcdir}/pcl-cvs.texinfo + +DVIPS=dvips +pcl-cvs.ps: pcl-cvs.dvi + ${DVIPS} pcl-cvs.dvi -o pcl-cvs.ps + +mostlyclean clean realclean: + rm -f *~ core $(ELCFILES) $(INFOFILES) $(TEXTMPS) + +tags TAGS: + etags *.el + +DISTFILES = \ + .cvsignore ChangeLog INSTALL Makefile.in NEWS README \ + ${ELFILES} ${ELCFILES} compile-all.el \ + pcl-cvs.texinfo texinfo.tex +OBJDIR_DISTFILES = pcl-cvs.aux pcl-cvs.ps + +dist-dir: ${OBJDIR_DISTFILES} ${DISTFILES} pcl-cvs.info + mkdir ${DISTDIR} + for i in ${DISTFILES}; do \ + ln $(srcdir)/$${i} ${DISTDIR}; \ + done + ln ${OBJDIR_DISTFILES} ${DISTDIR} + ln pcl-cvs.info* ${DISTDIR} +.PHONY: dist-dir + +subdir = contrib/pcl-cvs +Makefile: ../../config.status Makefile.in + cd ../.. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/NEWS b/gnu/usr.bin/cvs/contrib/pcl-cvs/NEWS new file mode 100644 index 00000000000..4f563ffc501 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/NEWS @@ -0,0 +1,113 @@ +This is the NEWS file for pcl-cvs, an Elisp front-end to CVS. + +User-visible changes in pcl-cvs from 1.04 to 1.05: + +* Elib is no longer distributed with pcl-cvs. You must get Elib + separately, for instance from ftp.lysator.liu.se in pub/emacs. + +* The Lucid Emacs support works again. + +* A new function, cvs-change-cvsroot, can be used to interactively + switch between CVS repositories. + +* The mode line in the *cvs* buffer now indicates when a "cvs update" + is running. + +* The .cvsignore file is automatically sorted alphabetically (to + reduce the risk of conflicts when two people add different files + simultaneously). This behaviour can be turned off with + cvs-sort-ignore-file. + +* A trailing newline is always added in commit log messages. This + behaviour can be turned off with + cvs-commit-buffer-require-final-newline. + +* This version of pcl-cvs should work together with RCVS. I have not + tested this myself, though. + +* Plus some bug fixes. (Note that the version of cookie.el that is + distributed with pcl-cvs 1.04 contains errors that affects pcl-cvs. + You should get Elib 0.07). + + +User-visible changes in pcl-cvs from 1.03 to 1.04: + +* Support for Emerge. Hitting "e" on a file that is Modified, Merged + or in Conflict will start Emerge, an interactive file merger written + in Emacs Lisp. This requires Emerge version 4. Emerge is not + included in this package. If you can't find it anywhere else, you + can get in from ftp.lysator.liu.se in pub/emacs. This package makes + it a lot easier to resolve conflicts. + +* Emacs will now automatically revert your buffers when the CVS + commands pcl-cvs issues causes the file to change. This automatic + revert never occurs if the buffer contents did not agree with the + file prior to the command. + +* If you are running Lucid GNU Emacs, you will get some fonts and + mouse support. This was contributed from people at Lucid. + +* The variable cvs-cvsroot can be used to select the location if the + repository. You no longer need to exit Emacs, setenv CVSROOT, and + start a new Emacs if you work with multiple repositories. + +* The "q" key can be used to hide the *cvs* buffer. + +* The name of the commands in the *cvs* have changed. If it was called + cvs-foo, it will now be called cvs-mode-foo. See the ChangeLog + entry from Tue Aug 4 03:02:25 1992 for a complete list of changes. + +* The variable cvs-cvs-diff-flags is no longer used. Instead, + cvs-diff-flags is always used. + +* Plus a lot of bug fixes. + + +User-visible changes in pcl-cvs from 1.02 to 1.03: + +* Output from CVS to stdout and stderr is separated and parsed + independently. In that way pcl-cvs should work regardless of + whether stdout is buffered or line-buffered. Pcl-cvs should now + work with CVS 1.3 without modifications on hosts such as + DECstations. + +* Pcl-cvs now fully supports RCS version 5.6 as well as 5.5. + +* New functions: + + + cvs-undo-local-changes ("U") - Undo all your modifications + to a file and get the newest + version from the repository. + + cvs-update-other-window - Similar to cvs-update. + + cvs-byte-compile-files - Byte compile the selected files. + +* cvs-update now displays the *cvs* buffer, which initially contains a + small message ("Running `cvs update' in /foo/bar/gazonk/...") until + the update is ready. The *cvs* buffer no longer pops up when the + update is ready. It often failed to pop up, due to race conditions + that are very hard to solve (and I doubt that they were at all + solvable). + +* cvs-unmark-all-files is moved from "U" to "ESC DEL" to be + "compatible" with dired. + +* cvs-diff ("d") and cvs-diff-backup ("b") can be configured to work + on only the file the cursor is positioned on, and ignore any marked + files. A prefix argument toggles this. + +* Only one `cvs update' can be run at a time. (It was previously + possible to start more than one simultaneously, but pcl-cvs could + not really handle more than one.) + +* Some rudimentary support for programs that CVS runs at update (due + to the -u switch in the modules file). + +* Pcl-cvs now automatically generates a bug report if it can't parse + the output from CVS. + +* The *cvs* buffer is read-only. + +* Pcl-cvs now creates temporary files in $TMPDIR if that environment + variable is set (otherwise it uses /tmp). + +---End of file NEWS--- 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 00000000000..a9b81066137 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/README @@ -0,0 +1,29 @@ +@(#) Id: README,v 1.14 1993/05/31 22:43:36 ceder Exp + +This is the readme file for pcl-cvs, release 1.05. + +This release of pcl-cvs requires Elib 0.07 or later. Elib is no +longer distributed with pcl-cvs, since that caused too much confusion. +You can get Elib from ftp.lysator.liu.se in pub/emacs/elib-*.tar.?. + +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 +version 2 or 3 a preformatted info file is also included (pcl-cvs.info). + +If you have been using a previous version of pcl-cvs (for instance +1.02 which is distributed with CVS 1.3) you should read through the +file NEWS to see what has changed. + +This release has been tested under Emacs 18.59, Emacs 19.28 and Lucid +Emacs 19.6. Emacs 19.10 unfortunately has a file named cookie.el that +collides with the cookie.el that is distributed in Elib. This +conflict was resolved in 19.11. For earlier versions, there are +instructions in Elib 0.07 for how to work around the problem. + + Per Cederqvist + (updated by Jim Blandy) 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 00000000000..65632775085 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/compile-all.el @@ -0,0 +1,52 @@ +;;;; @(#) Id: compile-all.el,v 1.11 1993/05/31 18:40:25 ceder Exp +;;;; This file byte-compiles all .el files in pcl-cvs release 1.05. +;;;; +;;;; Copyright (C) 1991 Inge Wallin +;;;; +;;;; This file was once upon a time part of Elib, but have since been +;;;; modified by Per Cederqvist. +;;;; +;;;; 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 files-to-compile '("pcl-cvs" "pcl-cvs-lucid")) + + +(defun compile-file-if-necessary (file) + "Compile 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 pcl-cvs." + + (interactive) + + ;; Be sure to have . in load-path since a number of files + ;; depend on other files and we always want the newer one even if + ;; a previous version of pcl-cvs exists. + (let ((load-path (append '(".") load-path))) + + (mapcar (function compile-file-if-necessary) + files-to-compile))) diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-lucid.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-lucid.el new file mode 100644 index 00000000000..d1f69e313d4 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-lucid.el @@ -0,0 +1,133 @@ +;;; Mouse and font support for PCL-CVS 1.3 running in Lucid GNU Emacs +;; @(#) Id: pcl-cvs-lucid.el,v 1.2 1993/05/31 19:37:34 ceder Exp +;; Copyright (C) 1992-1993 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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. + + +;; This simply adds a menu of the common CVS commands to the menubar and to +;; the right mouse button. Clicking right moves point, and then pops up a +;; menu from which commands can be executed. +;; +;; This could stand to be a lot more clever: for example, the "Commit Changes" +;; command should only be active on files for which there is something to +;; commit. Also, some indication of which files the command applies to +;; (especially in the presence of multiple marked files) would be nice. +;; +;; Middle-click runs find-file. + + +(require 'pcl-cvs) + +(defvar cvs-menu + '("CVS" + ["Find File" cvs-mode-find-file t] + ["Find File Other Window" cvs-mode-find-file-other-window t] + ["Interactively Merge (emerge)" cvs-mode-emerge t] + ["Diff against Repository" cvs-mode-diff-cvs t] + ["Diff against Backup Version" cvs-mode-diff-backup t] + "----" + ["Commit Changes to Repository" cvs-mode-commit t] + ["Revert File from Repository" cvs-mode-undo-local-changes t] + ["Add File to Repository" cvs-mode-add t] + ["Remove File from Repository" cvs-mode-remove-file t] + ["Ignore File" cvs-mode-ignore t] + ["Hide File" cvs-mode-acknowledge t] + ["Hide Handled Files" cvs-mode-remove-handled t] + "----" + ["Add ChangeLog Entry" cvs-mode-add-change-log-entry-other-window t] + ["Show CVS Log" cvs-mode-log t] + ["Show CVS Status" cvs-mode-status t] + "----" + ["Mark File" cvs-mode-mark t] + ["Unmark File" cvs-mode-unmark t] + ["Mark All Files" cvs-mode-mark-all-files t] + ["Unmark All Files" cvs-mode-unmark-all-files t] + "----" + ["Quit" bury-buffer t] + )) + +(defun cvs-menu (e) + (interactive "e") + (mouse-set-point e) + (beginning-of-line) + (or (looking-at "^[* ] ") (error "No CVS file line here")) + (popup-menu cvs-menu)) + +(defun cvs-mouse-find-file (e) + (interactive "e") + (mouse-set-point e) + (beginning-of-line) + (or (looking-at "^[* ] ") (error "No CVS file line here")) + (cvs-mode-find-file (point))) + +(define-key cvs-mode-map 'button3 'cvs-menu) +(define-key cvs-mode-map 'button2 'cvs-mouse-find-file) + +(make-face 'cvs-header-face) +(make-face 'cvs-filename-face) +(make-face 'cvs-status-face) + +(or (face-differs-from-default-p 'cvs-header-face) + (copy-face 'italic 'cvs-header-face)) + +(or (face-differs-from-default-p 'cvs-filename-face) + (copy-face 'bold 'cvs-filename-face)) + +(or (face-differs-from-default-p 'cvs-status-face) + (copy-face 'bold-italic 'cvs-status-face)) + + +(defun pcl-mode-motion-highlight-line (event) + (if (save-excursion + (let* ((window (event-window event)) + (buffer (and window (window-buffer window))) + (point (and buffer (event-point event)))) + (and point + (progn + (set-buffer buffer) + (goto-char point) + (beginning-of-line) + (looking-at "^[* ] "))))) + (mode-motion-highlight-line event))) + +(defconst pcl-cvs-font-lock-keywords + '(("^In directory \\(.+\\)$" 1 cvs-header-face) + ("^[* ] \\w+ +\\(ci\\)" 1 cvs-status-face) + ("^[* ] \\(Conflict\\|Merged\\)" 1 cvs-status-face) + ("^[* ] \\w+ +\\(ci +\\)?\\(.+\\)$" 2 cvs-filename-face) + ) + "Patterns to highlight in the *cvs* buffer.") + +(defun pcl-cvs-fontify () + ;; + ;; set up line highlighting + (require 'mode-motion) + (setq mode-motion-hook 'pcl-mode-motion-highlight-line) + ;; + ;; set up menubar + (if (and current-menubar (not (assoc "CVS" current-menubar))) + (progn + (set-buffer-menubar (copy-sequence current-menubar)) + (add-menu nil "CVS" (cdr cvs-menu)))) + ;; + ;; fontify mousable lines + (set (make-local-variable 'font-lock-keywords) pcl-cvs-font-lock-keywords) + (font-lock-mode 1) + ) + +(add-hook 'cvs-mode-hook 'pcl-cvs-fontify) 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 00000000000..f9b2de0418a --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-startup.el @@ -0,0 +1,14 @@ +;;; @(#) Id: pcl-cvs-startup.el,v 1.4 1993/05/31 18:40:33 ceder 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) + +(autoload 'cvs-update-other-window "pcl-cvs" + "Run a 'cvs update' in the current working directory. Feed the +output to a *cvs* buffer, display it in the other window, 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.aux b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.aux new file mode 100644 index 00000000000..ce14e5a0f92 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.aux @@ -0,0 +1,99 @@ +'xrdef {Copying-title}{GNU GENERAL PUBLIC LICENSE} +'xrdef {Copying-pg}{1} +'xrdef {Copying-snt}{} +'xrdef {Installation-title}{Installation} +'xrdef {Installation-pg}{9} +'xrdef {Installation-snt}{Chapter'tie1} +'xrdef {Pcl-cvs installation-title}{Installation of the pcl-cvs program} +'xrdef {Pcl-cvs installation-pg}{9} +'xrdef {Pcl-cvs installation-snt}{Section'tie1.1} +'xrdef {On-line manual installation-title}{Installation of the on-line manual.} +'xrdef {On-line manual installation-pg}{10} +'xrdef {On-line manual installation-snt}{Section'tie1.2} +'xrdef {Typeset manual installation-title}{How to make typeset documentation from pcl-cvs.texinfo} +'xrdef {Typeset manual installation-pg}{10} +'xrdef {Typeset manual installation-snt}{Section'tie1.3} +'xrdef {About pcl-cvs-title}{About pcl-cvs} +'xrdef {About pcl-cvs-pg}{11} +'xrdef {About pcl-cvs-snt}{Chapter'tie2} +'xrdef {Contributors-title}{Contributors to pcl-cvs} +'xrdef {Contributors-pg}{11} +'xrdef {Contributors-snt}{Section'tie2.1} +'xrdef {Archives-title}{Where can I get pcl-cvs?} +'xrdef {Archives-pg}{11} +'xrdef {Archives-snt}{Section'tie2.2} +'xrdef {Getting started-title}{Getting started} +'xrdef {Getting started-pg}{12} +'xrdef {Getting started-snt}{Chapter'tie3} +'xrdef {Buffer contents-title}{Buffer contents} +'xrdef {Buffer contents-pg}{14} +'xrdef {Buffer contents-snt}{Chapter'tie4} +'xrdef {File status-title}{File status} +'xrdef {File status-pg}{14} +'xrdef {File status-snt}{Section'tie4.1} +'xrdef {Selected files-title}{Selected files} +'xrdef {Selected files-pg}{15} +'xrdef {Selected files-snt}{Section'tie4.2} +'xrdef {Commands-title}{Commands} +'xrdef {Commands-pg}{16} +'xrdef {Commands-snt}{Chapter'tie5} +'xrdef {Updating the directory-title}{Updating the directory} +'xrdef {Updating the directory-pg}{16} +'xrdef {Updating the directory-snt}{Section'tie5.1} +'xrdef {Movement commands-title}{Movement Commands} +'xrdef {Movement commands-pg}{16} +'xrdef {Movement commands-snt}{Section'tie5.2} +'xrdef {Marking files-title}{Marking files} +'xrdef {Marking files-pg}{17} +'xrdef {Marking files-snt}{Section'tie5.3} +'xrdef {Committing changes-title}{Committing changes} +'xrdef {Committing changes-pg}{17} +'xrdef {Committing changes-snt}{Section'tie5.4} +'xrdef {Editing files-title}{Editing files} +'xrdef {Editing files-pg}{18} +'xrdef {Editing files-snt}{Section'tie5.5} +'xrdef {Getting info about files-title}{Getting info about files} +'xrdef {Getting info about files-pg}{18} +'xrdef {Getting info about files-snt}{Section'tie5.6} +'xrdef {Adding and removing files-title}{Adding and removing files} +'xrdef {Adding and removing files-pg}{18} +'xrdef {Adding and removing files-snt}{Section'tie5.7} +'xrdef {Undoing changes-title}{Undoing changes} +'xrdef {Undoing changes-pg}{19} +'xrdef {Undoing changes-snt}{Section'tie5.8} +'xrdef {Removing handled entries-title}{Removing handled entries} +'xrdef {Removing handled entries-pg}{19} +'xrdef {Removing handled entries-snt}{Section'tie5.9} +'xrdef {Ignoring files-title}{Ignoring files} +'xrdef {Ignoring files-pg}{20} +'xrdef {Ignoring files-snt}{Section'tie5.10} +'xrdef {Viewing differences-title}{Viewing differences} +'xrdef {Viewing differences-pg}{20} +'xrdef {Viewing differences-snt}{Section'tie5.11} +'xrdef {Emerge-title}{Running emerge} +'xrdef {Emerge-pg}{20} +'xrdef {Emerge-snt}{Section'tie5.12} +'xrdef {Reverting your buffers-title}{Reverting your buffers} +'xrdef {Reverting your buffers-pg}{21} +'xrdef {Reverting your buffers-snt}{Section'tie5.13} +'xrdef {Miscellaneous commands-title}{Miscellaneous commands} +'xrdef {Miscellaneous commands-pg}{21} +'xrdef {Miscellaneous commands-snt}{Section'tie5.14} +'xrdef {Customization-title}{Customization} +'xrdef {Customization-pg}{22} +'xrdef {Customization-snt}{Chapter'tie6} +'xrdef {Future enhancements-title}{Future enhancements} +'xrdef {Future enhancements-pg}{24} +'xrdef {Future enhancements-snt}{Chapter'tie7} +'xrdef {Bugs-title}{Bugs (known and unknown)} +'xrdef {Bugs-pg}{26} +'xrdef {Bugs-snt}{Chapter'tie8} +'xrdef {Function and Variable Index-title}{Function and Variable Index} +'xrdef {Function and Variable Index-pg}{27} +'xrdef {Function and Variable Index-snt}{} +'xrdef {Concept Index-title}{Concept Index} +'xrdef {Concept Index-pg}{28} +'xrdef {Concept Index-snt}{} +'xrdef {Key Index-title}{Key Index} +'xrdef {Key Index-pg}{30} +'xrdef {Key Index-snt}{} 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 00000000000..6e02183aaa0 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.el @@ -0,0 +1,2485 @@ +;;; @(#) Id: pcl-cvs.el,v 1.93 1993/05/31 22:44:00 ceder Exp +;;; pcl-cvs.el -- A Front-end to CVS 1.3 or later. Release 1.05. +;;; Copyright (C) 1991, 1992, 1993 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. + +;;;; Send bug reports and improvements to ceder@lysator.liu.se or +;;;; ceder@signum.se. Talk some about Signum Support here. +++FIXME + +;;; Don't try to use this with CVS 1.2 or earlier. It won't work. Get +;;; CVS 1.3. This package works together with RCS 5.6 and probably 5.5 +;;; as well. + +;;; 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/local/bin/cvs" + "*Full path to the cvs executable.") + +(defvar cvs-diff-program "/usr/local/bin/diff" + "*Full path to the diff program.") + +(defvar cvs-rmdir-program "/bin/rmdir" + "*Full path to the rmdir program. Typically /bin/rmdir.") + +;; 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. + +(defvar cvs-shell "/bin/sh" + "*Full path to a shell that can do redirection on stdout.") + +;;; END OF THINGS TO CHECK WHEN INSTALLING +;;; -------------------------------------------------------- + +(defvar cvs-cvsroot nil + "*Specifies where the (current) cvs master repository is. +Overrides the $CVSROOT variable by sending \" -d dir\" to all cvs commands. +This switch is useful if you have multiple CVS repositories.") + +(defvar cvs-cvsroot-required t + "*Specifies whether CVS needs to be told where the repository is. + +In CVS 1.3, if your CVSROOT environment variable is not set, and you +do not set the `cvs-cvsroot' lisp variable, CVS will have no idea +where to find the repository, and refuse to run. CVS 1.4 and later +store the repository path with the working directories, so most +operations don't need to be told where the repository is. + +If you work with multiple repositories with CVS 1.4, it's probably +advisable to leave your CVSROOT environment variable unset, set this +variable to nil, and let CVS figure out where the repository is for +itself.") + +(defvar cvs-stdout-file nil + "Name of the file that holds the output that CVS sends to stdout. +This variable is buffer local.") + +(defvar cvs-lock-file nil + "Full path to a lock file that CVS is waiting for (or was waiting for).") + +(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-mode-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-mode-commit +command.") + +(defvar cvs-sort-ignore-file t + "*Non-nil if cvs-mode-ignore should sort the .cvsignore automatically.") + +(defvar cvs-auto-revert-after-commit t + "*Non-nil if committed buffers should be automatically reverted.") + +(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-commit-buffer-require-final-newline t + "*t says silently put a newline at the end of commit log messages. +Non-nil but not t says ask user whether to add a newline in each such case. +nil means don't add newlines.") + +(defvar cvs-temp-buffer-name "*cvs-tmp*" + "*Name of the cvs temporary buffer. +Output from cvs is placed here by synchronous commands.") + +(defvar cvs-diff-ignore-marks nil + "*Non-nil if cvs-diff and cvs-mode-diff-backup should ignore any marked files. +Normally they run diff on the files that are marked (with cvs-mode-mark), +or the file under the cursor if no files are marked. If this variable +is set to a non-nil value they will always run diff on the file on the +current line.") + +(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'' and ``cvs diff''. +Used by cvs-mode-diff-cvs and cvs-mode-diff-backup. +Set this to '(\"-u\") to get a Unidiff format, or '(\"-c\") to get context diffs.") + +(defvar cvs-update-prog-output-skip-regexp "$" + "*A regexp that matches the end of the output from all cvs update programs. +That is, output from any programs that are run by CVS (by the flag -u +in the `modules' file - see cvs(5)) when `cvs update' is performed should +terminate with a line that this regexp matches. It is enough that +some part of the line is matched. + +The default (a single $) fits programs without output.") + +;; The variables below are used internally by pcl-cvs. You should +;; never change them. + +(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 + "*Non-nil means don't display a Copyright message in the ``*cvs*'' buffer.") + +(defconst pcl-cvs-version "1.05" + "A string denoting the current release version of pcl-cvs.") + +(defconst cvs-startup-message + (if cvs-inhibit-copyright-message + "PCL-CVS release 1.05" + "PCL-CVS release 1.05. Copyright (C) 1992, 1993 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-update-running nil + "This is set to nil when no process is running, and to +the process when a cvs update process is running.") + +(defvar cvs-cookie-handle nil + "Handle for the cookie structure that is displayed in the *cvs* buffer.") + +(defvar cvs-mode-commit nil + "Used internally by pcl-cvs.") + +;;; 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. +;;; REM-EXIST -removed locally, but still exists. +;;; 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. +;;; MESSAGE - This is a special fileinfo that is used +;;; to display a text that should be in +;;; full-log. +;;; dir Directory the file resides in. Should not end with +;;; slash. +;;; file-name The file name. +;;; base-revision The revision that the working file was based on. +;;; Only valid for MERGED and CONFLICT files. +;;; 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. + REM-EXIST - removed locally, but still exists. + 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. + MESSAGE - This is a special fileinfo that is used + to display a text that should be in + full-log. + 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, REM-EXIST, DIRCHANGE, UNKNOWN, MOVE-AWAY, +REPOS-MISSING or MESSAGE." + (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->base-revision (cvs-fileinfo) + "Get the base revision 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->base-revision (cvs-fileinfo newval) + "Set base-revision 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." + + (let ((dir default-directory)) + (display-buffer (get-buffer-create cvs-temp-buffer-name)) + (set-buffer cvs-temp-buffer-name) + (setq buffer-read-only nil) + (setq default-directory dir) + (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) + (switch-to-buffer cvs-buffer-name)) + +(defun cvs-update-other-window (directory &optional local) + "Run a 'cvs update' in the current working directory. Feed the +output to a *cvs* buffer, display it in the other window, 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 other window (directory): " + nil default-directory nil) + current-prefix-arg)) + (cvs-do-update directory local nil) + (switch-to-buffer-other-window cvs-buffer-name)) + +(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-mode-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. +Args: DIRECTORY LOCAL DONT-CHANGE-DISC &optional NOTTHISWINDOW. +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) + (if (not (file-exists-p cvs-program)) + (error "%s: file not found (check setting of cvs-program)" + cvs-program)) + (if (and cvs-cvsroot-required + (not (or (getenv "CVSROOT") cvs-cvsroot))) + (error "Both cvs-cvsroot and environment variable CVSROOT unset.")) + (let* ((this-dir (file-name-as-directory (expand-file-name directory))) + (update-buffer (generate-new-buffer + (concat (file-name-nondirectory + (substring this-dir 0 -1)) + "-update"))) + (temp-name (make-temp-name + (concat (file-name-as-directory + (or (getenv "TMPDIR") "/tmp")) + "pcl-cvs."))) + (args nil)) + + ;; Check that this-dir exists and is a directory that is under CVS contr. + + (if (not (file-directory-p this-dir)) + (error "%s is not a directory." this-dir)) + (if (not (file-directory-p (concat this-dir "CVS"))) + (error "%s does not contain CVS controlled files." this-dir)) + + ;; Check that at most one `cvs update' is run at any time. + + (if (and cvs-update-running (process-status cvs-update-running) + (or (eq (process-status cvs-update-running) 'run) + (eq (process-status cvs-update-running) 'stop))) + (error "Can't run two `cvs update' simultaneously.")) + + ;; Generate "-d /master -n update -l". + (setq args (concat (if cvs-cvsroot (concat " -d " cvs-cvsroot)) + (if dont-change-disc " -n ") + " update " + (if local " -l "))) + + ;; Set up the buffer that receives the stderr output from "cvs update". + (set-buffer update-buffer) + (setq default-directory this-dir) + (make-local-variable 'cvs-stdout-file) + (setq cvs-stdout-file temp-name) + + (setq cvs-update-running + (let ((process-connection-type nil)) ; Use a pipe, not a pty. + (start-process "cvs" update-buffer cvs-shell "-c" + (concat cvs-program " " args " > " temp-name)))) + + (setq mode-line-process + (concat ": " + (symbol-name (process-status cvs-update-running)))) + (set-buffer-modified-p (buffer-modified-p)) ; Update the mode line. + (set-process-sentinel cvs-update-running 'cvs-sentinel) + (set-process-filter cvs-update-running 'cvs-update-filter) + (set-marker (process-mark cvs-update-running) (point-min)) + + (save-excursion + (set-buffer (get-buffer-create cvs-buffer-name)) + (setq buffer-read-only nil) + (erase-buffer) + (cvs-mode)) + + (setq cvs-cookie-handle + (collection-create + cvs-buffer-name 'cvs-pp + cvs-startup-message ;Se comment above cvs-startup-message. + "---------- End -----")) + + (cookie-enter-first + cvs-cookie-handle + (cvs-create-fileinfo + 'MESSAGE nil nil (concat "\n Running `cvs " args "' in " this-dir + "...\n"))) + + (save-excursion + (set-buffer cvs-buffer-name) + (setq mode-line-process + (concat ": " + (symbol-name (process-status cvs-update-running)))) + (set-buffer-modified-p (buffer-modified-p)) ; Update the mode line. + (setq buffer-read-only t)) + + ;; Work around a bug in emacs 18.57 and earlier. + (setq cvs-buffers-to-delete + (cvs-delete-unused-temporary-buffers cvs-buffers-to-delete))) + + ;; The following line is said to improve display updates on some + ;; emacses. It shouldn't be needed, but it does no harm. + (sit-for 0)) + + +(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: + +\\[cvs-mode-previous-line] Move up. \\[cvs-mode-next-line] Move down. +\\[cvs-mode-commit] Commit file. \\[cvs-mode-update-no-prompt] Reupdate directory. +\\[cvs-mode-mark] Mark file/dir. \\[cvs-mode-unmark] Unmark file/dir. +\\[cvs-mode-mark-all-files] Mark all files. \\[cvs-mode-unmark-all-files] Unmark all files. +\\[cvs-mode-find-file] Edit file/run Dired. \\[cvs-mode-find-file-other-window] Find file or run Dired in other window. +\\[cvs-mode-remove-handled] Remove processed entries. \\[cvs-mode-add-change-log-entry-other-window] Write ChangeLog in other window. +\\[cvs-mode-add] Add to repository. \\[cvs-mode-remove-file] Remove file. +\\[cvs-mode-diff-cvs] Diff between base revision. \\[cvs-mode-diff-backup] Diff backup file. +\\[cvs-mode-emerge] Run emerge on base revision/backup file. +\\[cvs-mode-acknowledge] Delete line from buffer. \\[cvs-mode-ignore] Add file to the .cvsignore file. +\\[cvs-mode-log] Run ``cvs log''. \\[cvs-mode-status] Run ``cvs status''. +\\[cvs-mode-changelog-commit] Like \\[cvs-mode-commit], but get default log text from ChangeLog. +\\[cvs-mode-undo-local-changes] Revert the last checked in version - discard your changes to the file. + +Entry to this mode runs cvs-mode-hook. +This description is updated for release 1.05 of pcl-cvs. + +All bindings: +\\{cvs-mode-map}" + (interactive) + (setq major-mode 'cvs-mode) + (setq mode-name "CVS") + (setq mode-line-process 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)))) + (let* ((out-file cvs-stdout-file) + (stdout-buffer (find-file-noselect out-file))) + (cvs-parse-update stdout-buffer (process-buffer proc)) + (setq cvs-buffers-to-delete + (cons (process-buffer proc) + (cons stdout-buffer + cvs-buffers-to-delete))) + (delete-file out-file))) + (set-buffer-modified-p (buffer-modified-p)) + (setq cvs-update-running nil)) + (if (equal obuf (process-buffer proc)) + nil + (set-buffer (process-buffer proc)) + (if (< opoint omax) + (goto-char opoint)) + (set-buffer obuf)))))) + +(defun cvs-update-filter (proc string) + "Filter function for pcl-cvs. +This function gets the output that CVS sends to stderr. It inserts it +into (process-buffer proc) but it also checks if CVS is waiting for a +lock file. If so, it inserts a message cookie in the *cvs* buffer." + (let ((old-buffer (current-buffer)) + (data (match-data))) + (unwind-protect + (progn + (set-buffer (process-buffer proc)) + (save-excursion + ;; Insert the text, moving the process-marker. + (goto-char (process-mark proc)) + (insert string) + (set-marker (process-mark proc) (point)) + ;; Delete any old lock message + (if (tin-nth cvs-cookie-handle 1) + (tin-delete cvs-cookie-handle + (tin-nth cvs-cookie-handle 1))) + ;; Check if CVS is waiting for a lock. + (beginning-of-line 0) ;Move to beginning of last + ;complete line. + (cond + ((looking-at + "^cvs update: \\[..:..:..\\] waiting \ +for \\(.*\\)lock in \\(.*\\)$") + (setq cvs-lock-file (buffer-substring (match-beginning 2) + (match-end 2))) + (cookie-enter-last + cvs-cookie-handle + (cvs-create-fileinfo + 'MESSAGE nil nil + (concat "\tWaiting for " + (buffer-substring (match-beginning 1) + (match-end 1)) + "lock in " cvs-lock-file + ".\n\t (type M-x cvs-delete-lock to delete it)"))))))) + (store-match-data data) + (set-buffer old-buffer)))) + +(defun cvs-delete-lock () + "Delete the lock file that CVS is waiting for. +Note that this can be dangerous. You should only do this +if you are convinced that the process that created the lock is dead." + (interactive) + (cond + ((not (or (file-exists-p + (concat (file-name-as-directory cvs-lock-file) "#cvs.lock")) + (cvs-filter (function cvs-lock-file-p) + (directory-files cvs-lock-file)))) + (error "No lock files found.")) + ((yes-or-no-p (concat "Really delete locks in " cvs-lock-file "? ")) + ;; Re-read the directory -- the locks might have disappeared. + (let ((locks (cvs-filter (function cvs-lock-file-p) + (directory-files cvs-lock-file)))) + (while locks + (delete-file (concat (file-name-as-directory cvs-lock-file) + (car locks))) + (setq locks (cdr locks))) + (cvs-remove-directory + (concat (file-name-as-directory cvs-lock-file) "#cvs.lock")))))) + +(defun cvs-remove-directory (dir) + "Remove a directory." + (if (file-directory-p dir) + (call-process cvs-rmdir-program nil nil nil dir) + (error "Not a directory: %s" dir)) + (if (file-exists-p dir) + (error "Could not remove directory %s" dir))) + +(defun cvs-lock-file-p (file) + "Return true if FILE looks like a CVS lock file." + (or + (string-match "^#cvs.tfl.[0-9]+$" file) + (string-match "^#cvs.rfl.[0-9]+$" file) + (string-match "^#cvs.wfl.[0-9]+$" file))) + +(defun cvs-skip-line (stdout stderr regexp &optional arg) + "Like forward-line, but check that the skipped line matches REGEXP. +Args: STDOUT STDERR REGEXP &optional ARG. + +If it doesn't match REGEXP a bug report is generated and displayed. +STDOUT and STDERR is only used to do that. + +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 + (cvs-parse-error stdout stderr + (if (eq (current-buffer) stdout) 'STDOUT 'STDERR) + (point))))) + +(defun cvs-get-current-dir (root-dir dirname) + "Return current working directory, suitable for cvs-parse-update. +Args: ROOT-DIR DIRNAME. +Concatenates ROOT-DIR and DIRNAME to form an absolute path." + (if (string= "." dirname) + (substring root-dir 0 -1) + (concat root-dir dirname))) + +(defun cvs-compare-fileinfos (a b) + "Compare fileinfo A with fileinfo B and return t if A is `less'." + (cond + ;; Sort acording to directories. + ((string< (cvs-fileinfo->dir a) (cvs-fileinfo->dir b)) t) + ((not (string= (cvs-fileinfo->dir a) (cvs-fileinfo->dir b))) nil) + + ;; The DIRCHANGE entry is always first within the directory. + ((and (eq (cvs-fileinfo->type a) 'DIRCHANGE) + (not (eq (cvs-fileinfo->type b) 'DIRCHANGE))) t) + ((and (eq (cvs-fileinfo->type b) 'DIRCHANGE) + (not (eq (cvs-fileinfo->type a) 'DIRCHANGE))) nil) + ;; All files are sorted by file name. + ((string< (cvs-fileinfo->file-name a) (cvs-fileinfo->file-name b))))) + +(defun cvs-parse-error (stdout-buffer stderr-buffer err-buf pos) + "Handle a parse error when parsing the output from cvs. +Args: STDOUT-BUFFER STDERR-BUFFER ERR-BUF POS. +ERR-BUF should be 'STDOUT or 'STDERR." + (setq pos (1- pos)) + (set-buffer cvs-buffer-name) + (setq buffer-read-only nil) + (erase-buffer) + (insert "To: ceder@lysator.liu.se\n") + (insert "Subject: pcl-cvs " pcl-cvs-version " parse error.\n") + (insert "--text follows this line--\n\n") + (insert "This bug report is automatically generated by pcl-cvs\n") + (insert "because it doesn't understand some output from CVS. Below\n") + (insert "is detailed information about the error. Please send\n") + (insert "this, together with any information you think might be\n") + (insert "useful for me to fix the bug, to the address above. But\n") + (insert "please check the \"known problems\" section of the\n") + (insert "documentation first. Note that this buffer contains\n") + (insert "information that you might consider confidential. You\n") + (insert "are encouraged to read through it before sending it.\n") + (insert "\n") + (insert "Press C-c C-c to send this email.\n\n") + (insert "Please state the version of these programs you are using:\n") + (insert "RCS: \ndiff: \n\n") + + (let* ((stdout (save-excursion (set-buffer stdout-buffer) (buffer-string))) + (stderr (save-excursion (set-buffer stderr-buffer) (buffer-string))) + (errstr (if (eq err-buf 'STDOUT) stdout stderr)) + (errline-end (string-match "\n" errstr pos)) + (errline (substring errstr pos errline-end))) + (insert (format "Offending line (%d chars): >" (- errline-end pos))) + (insert errline) + (insert "<\n") + (insert "Sent to " (symbol-name err-buf) " at pos " (format "%d\n" pos)) + (insert "Emacs-version: " (emacs-version) "\n") + (insert "Pcl-cvs $" "Id:" "$" ": " "Id: pcl-cvs.el,v 1.93 1993/05/31 22:44:00 ceder Exp \n") + (insert "\n") + (insert (format "--- Contents of stdout buffer (%d chars) ---\n" + (length stdout))) + (insert stdout) + (insert "--- End of stdout buffer ---\n") + (insert (format "--- Contents of stderr buffer (%d chars) ---\n" + (length stderr))) + (insert stderr) + (insert "--- End of stderr buffer ---\n") + (insert "End of bug report.\n") + (require 'sendmail) + (mail-mode) + (error "CVS parse error - please report this bug."))) + +(defun cvs-parse-update (stdout-buffer stderr-buffer) + "Parse the output from `cvs update'. + +Args: STDOUT-BUFFER STDERR-BUFFER. + +This functions parses the from `cvs update' (which should be +separated in its stdout- and stderr-components) and prints a +pretty representation of it in the *cvs* buffer. + +Signals an error if unexpected output was detected in the buffer." + (let* ((head (cons 'dummy nil)) + (tail (cvs-parse-stderr stdout-buffer stderr-buffer + head default-directory)) + (root-dir default-directory)) + (cvs-parse-stdout stdout-buffer stderr-buffer tail root-dir) + (setq head (sort (cdr head) (function cvs-compare-fileinfos))) + + (collection-clear cvs-cookie-handle) + (collection-append-cookies cvs-cookie-handle head) + (cvs-remove-stdout-shadows) + (cvs-remove-empty-directories) + (set-buffer cvs-buffer-name) + (cvs-mode) + (goto-char (point-min)) + (tin-goto-previous cvs-cookie-handle (point-min) 1) + (setq default-directory root-dir))) + +(defun cvs-remove-stdout-shadows () + "Remove entries in the *cvs* buffer that comes from both stdout and stderr. +If there is two entries for a single file the second one should be +deleted. (Remember that sort uses a stable sort algorithm, so one can +be sure that the stderr entry is always first)." + (collection-filter-tins cvs-cookie-handle + (function + (lambda (tin) + (not (cvs-shadow-entry-p tin)))))) + +(defun cvs-shadow-entry-p (tin) + "Return non-nil if TIN is a shadow entry. +Args: TIN. +A TIN is a shadow entry if the previous tin contains the same file." + (let* ((previous-tin (tin-previous cvs-cookie-handle tin)) + (curr (tin-cookie cvs-cookie-handle tin)) + (prev (and previous-tin + (tin-cookie cvs-cookie-handle previous-tin)))) + (and + prev curr + (string= (cvs-fileinfo->file-name prev) (cvs-fileinfo->file-name curr)) + (string= (cvs-fileinfo->dir prev) (cvs-fileinfo->dir curr)) + (or + (and (eq (cvs-fileinfo->type prev) 'CONFLICT) + (eq (cvs-fileinfo->type curr) 'CONFLICT)) + (and (eq (cvs-fileinfo->type prev) 'MERGED) + (eq (cvs-fileinfo->type curr) 'MODIFIED)) + (and (eq (cvs-fileinfo->type prev) 'REM-EXIST) + (eq (cvs-fileinfo->type curr) 'REMOVED)))))) + + +(defun cvs-parse-stderr (stdout-buffer stderr-buffer head dir) + "Parse the output from CVS that is written to stderr. +Args: STDOUT-BUFFER STDERR-BUFFER HEAD DIR +STDOUT-BUFFER holds the output that cvs sent to stdout. It is only +used to create a bug report in case there is a parse error. +STDERR-BUFFER is the buffer that holds the output to parse. +HEAD is a cons-cell, the head of the list that is built. +DIR is the directory the `cvs update' was run in. + +This function returns the last cons-cell in the list that is built." + + (save-window-excursion + (set-buffer stderr-buffer) + (goto-char (point-min)) + (let ((current-dir dir) + (root-dir dir)) + + (while (< (point) (point-max)) + (cond + + ;; RCVS support (for now, we simply ignore any output from + ;; RCVS, including error messages!) + + ((looking-at "updating of .* finished$") + (forward-line 1)) + + ((looking-at "REMOTE FOLDER:.*") + (forward-line 1) + (while (and (< (point) (point-max)) (not (looking-at "phase 2.*"))) + (forward-line 1)) + (forward-line 2)) + + ((looking-at "turn on remote mode$") + (forward-line 1) + (while (and (< (point) (point-max)) (not (looking-at "phase 2.*"))) + (forward-line 1)) + (forward-line 2)) + + ((looking-at "phase 3.*") + (goto-char (point-max))) + + ;; End of RCVS stuff. + + ;; CVS is descending a subdirectory. + ;; (The "server" case is there to support Cyclic CVS.) + ((looking-at "cvs \\(update\\|server\\): Updating \\(.*\\)$") + (setq current-dir + (cvs-get-current-dir + root-dir + (buffer-substring (match-beginning 2) (match-end 2)))) + (setcdr head (list (cvs-create-fileinfo + 'DIRCHANGE current-dir + nil (buffer-substring (match-beginning 0) + (match-end 0))))) + (setq head (cdr head)) + (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")) + + (setcdr head (list (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))))) + (setq head (cdr head)) + (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$") + (setcdr head (list (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))))) + (setq head (cdr head)) + (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$") + (setcdr head (list + (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))))) + (setq head (cdr head)) + (forward-line 1)) + + ((looking-at + "cvs update: conflict: removed \\(.*\\) was modified by \ +second party") + (setcdr head + (list + (cvs-create-fileinfo + 'MOD-CONFLICT current-dir + (buffer-substring (match-beginning 1) (match-end 1)) + (buffer-substring (match-beginning 0) (match-end 0))))) + (setq head (cdr head)) + (forward-line 1)) + + ((looking-at + "cvs update: \\(.*\\) should be removed and is still there") + (setcdr head + (list + (cvs-create-fileinfo + 'REM-EXIST current-dir + (buffer-substring (match-beginning 1) (match-end 1)) + (buffer-substring (match-beginning 0) (match-end 0))))) + (setq head (cdr head)) + (forward-line 1)) + + ((looking-at "cvs update: in directory ") + (let ((start (point))) + (forward-line 1) + (cvs-skip-line + stdout-buffer stderr-buffer + (regexp-quote "cvs [update aborted]: there is no repository ")) + (setcdr head (list + (cvs-create-fileinfo + 'REPOS-MISSING current-dir + nil + (buffer-substring start (point))))) + (setq head (cdr head)))) + + ;; Ignore other messages from Cyclic CVS. + ((looking-at "cvs server:") + (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 stdout-buffer stderr-buffer "^RCS file: .*$") + (setq initial-revision + (cvs-skip-line stdout-buffer stderr-buffer + "^retrieving revision \\(.*\\)$" 1)) + (cvs-skip-line stdout-buffer stderr-buffer + "^retrieving revision .*$") + + ;; Get the file name from the next line. + + (setq + filename + (cvs-skip-line + stdout-buffer stderr-buffer + "^Merging differences between [0-9.]+ and [0-9.]+ into \\(.*\\)$" + 1)) + + (cond + ;; Was it a conflict? + ((looking-at + ;; Allow both RCS 5.5 and 5.6. (5.6 prints "rcs" and " warning"). + "^\\(rcs\\)?merge:?\\( warning\\)?: \\(overlaps\\|conflicts\\) during merge$") + + ;; Yes, this is a conflict. + (cvs-skip-line + stdout-buffer stderr-buffer + "^\\(rcs\\)?merge:?\\( warning\\)?: \\(overlaps\\|conflicts\\) during merge$") + + (cvs-skip-line stdout-buffer stderr-buffer + "^cvs \\(update\\|server\\): conflicts found in ") + + (let ((fileinfo + (cvs-create-fileinfo + 'CONFLICT current-dir + filename + (buffer-substring complex-start (point))))) + + (cvs-set-fileinfo->base-revision fileinfo initial-revision) + + (setcdr head (list fileinfo)) + (setq head (cdr head)))) + + ;; Was it a conflict, and was RCS compiled without DIFF3_BIN? + + ((looking-at + ;; Allow both RCS 5.5 and 5.6. (5.6 prints "rcs" and " warning"). + "^\\(rcs\\)?merge\\( warning\\)?: overlaps or other probl\ +ems during merge$") + + ;; Yes, this is a conflict. + (cvs-skip-line + stdout-buffer stderr-buffer + "^\\(rcs\\)?merge\\( warning\\)?: overlaps .*during merge$") + + (cvs-skip-line stdout-buffer stderr-buffer + "^cvs update: could not merge ") + (cvs-skip-line stdout-buffer stderr-buffer + "^cvs update: restoring .* from backup file ") + + (let ((fileinfo + (cvs-create-fileinfo + 'CONFLICT current-dir + filename + (buffer-substring complex-start (point))))) + + (setcdr head (list fileinfo)) + (setq head (cdr head)))) + + (t + ;; Not a conflict; it must be a succesful merge. + (let ((fileinfo + (cvs-create-fileinfo + 'MERGED current-dir + filename + (buffer-substring complex-start (point))))) + (cvs-set-fileinfo->base-revision fileinfo initial-revision) + (setcdr head (list fileinfo)) + (setq head (cdr head))))))))))) + head) + + +(defun cvs-parse-stdout (stdout-buffer stderr-buffer head root-dir) + "Parse the output from CVS that is written to stdout. +Args: STDOUT-BUFFER STDERR-BUFFER HEAD ROOT-DIR +STDOUT-BUFFER is the buffer that holds the output to parse. +STDERR-BUFFER holds the output that cvs sent to stderr. It is only +used to create a bug report in case there is a parse error. + +HEAD is a cons-cell, the head of the list that is built. +ROOT-DIR is the directory the `cvs update' was run in. + +This function doesn't return anything particular." + (save-window-excursion + (set-buffer stdout-buffer) + (goto-char (point-min)) + (while (< (point) (point-max)) + (cond + + ;; M: The file is modified by the user, and untouched in the repository. + ;; A: The file is "cvs add"ed, but not "cvs ci"ed. + ;; R: The file is "cvs remove"ed, but not "cvs ci"ed. + ;; C: Conflict + ;; U, P: The file is copied from the repository. + ;; ?: Unknown file. + + + ((looking-at "\\([MARCUP?]\\) \\(.*\\)$") + (let* + ((c (char-after (match-beginning 1))) + (full-path + (concat (file-name-as-directory root-dir) + (buffer-substring (match-beginning 2) (match-end 2)))) + (fileinfo (cvs-create-fileinfo + (cond ((eq c ?M) 'MODIFIED) + ((eq c ?A) 'ADDED) + ((eq c ?R) 'REMOVED) + ((eq c ?C) 'CONFLICT) + ((eq c ?U) 'UPDATED) + ;; generated when Cyclic CVS sends a + ;; patch instead of the full file: + ((eq c ?P) 'UPDATED) + ((eq c ??) 'UNKNOWN)) + (substring (file-name-directory full-path) 0 -1) + (file-name-nondirectory full-path) + (buffer-substring (match-beginning 0) (match-end 0))))) + ;; Updated files require no further action. + (if (memq c '(?U ?P)) + (cvs-set-fileinfo->handled fileinfo t)) + + ;; Link this last on the list. + (setcdr head (list fileinfo)) + (setq head (cdr head)) + (forward-line 1))) + + ;; Executing a program because of the -u option in modules. + ((looking-at "cvs update: Executing") + ;; Skip by any output the program may generate to stdout. + ;; Note that pcl-cvs will get seriously confused if the + ;; program prints anything to stderr. + (re-search-forward cvs-update-prog-output-skip-regexp) + (forward-line 1)) + + (t (cvs-parse-error stdout-buffer stderr-buffer 'STDOUT (point))))))) + +(defun cvs-pp (fileinfo) + "Pretty print FILEINFO. Insert a printed representation in current buffer. +For use by the cookie package." + + (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"))) + (insert + (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 'REM-EXIST) + (format "%s Conflict: Removed by you, but still exists: %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.")) + ((eq a 'MESSAGE) + (cvs-fileinfo->full-log fileinfo)) + (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 " " 'cvs-mode-next-line) + (define-key cvs-mode-map "?" 'describe-mode) + (define-key cvs-mode-map "A" 'cvs-mode-add-change-log-entry-other-window) + (define-key cvs-mode-map "M" 'cvs-mode-mark-all-files) + (define-key cvs-mode-map "R" 'cvs-mode-revert-updated-buffers) + (define-key cvs-mode-map "U" 'cvs-mode-undo-local-changes) + (define-key cvs-mode-map "\C-?" 'cvs-mode-unmark-up) + (define-key cvs-mode-map "\C-k" 'cvs-mode-acknowledge) + (define-key cvs-mode-map "\C-n" 'cvs-mode-next-line) + (define-key cvs-mode-map "\C-p" 'cvs-mode-previous-line) + (define-key cvs-mode-map "\M-\C-?" 'cvs-mode-unmark-all-files) + (define-key cvs-mode-map "a" 'cvs-mode-add) + (define-key cvs-mode-map "b" 'cvs-mode-diff-backup) + (define-key cvs-mode-map "c" 'cvs-mode-commit) + (define-key cvs-mode-map "C" 'cvs-mode-changelog-commit) + (define-key cvs-mode-map "d" 'cvs-mode-diff-cvs) + (define-key cvs-mode-map "e" 'cvs-mode-emerge) + (define-key cvs-mode-map "f" 'cvs-mode-find-file) + (define-key cvs-mode-map "g" 'cvs-mode-update-no-prompt) + (define-key cvs-mode-map "i" 'cvs-mode-ignore) + (define-key cvs-mode-map "l" 'cvs-mode-log) + (define-key cvs-mode-map "m" 'cvs-mode-mark) + (define-key cvs-mode-map "n" 'cvs-mode-next-line) + (define-key cvs-mode-map "o" 'cvs-mode-find-file-other-window) + (define-key cvs-mode-map "p" 'cvs-mode-previous-line) + (define-key cvs-mode-map "q" 'bury-buffer) + (define-key cvs-mode-map "r" 'cvs-mode-remove-file) + (define-key cvs-mode-map "s" 'cvs-mode-status) + (define-key cvs-mode-map "x" 'cvs-mode-remove-handled) + (define-key cvs-mode-map "u" 'cvs-mode-unmark)) + + +(defun cvs-get-marked (&optional ignore-marks) + "Return a list of all selected tins. +If there are any marked tins, and IGNORE-MARKS is nil, 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. + +Args: &optional IGNORE-MARKS." + + (cond + ;; Any marked cookies? + ((and (not ignore-marks) + (collection-collect-tin cvs-cookie-handle 'cvs-fileinfo->marked))) + ;; Nope. + (t + (let ((sel (tin-locate cvs-cookie-handle (point)))) + (cond + ;; If a directory is selected, all it members are returned. + ((and sel (eq (cvs-fileinfo->type + (tin-cookie cvs-cookie-handle sel)) + 'DIRCHANGE)) + (collection-collect-tin + cvs-cookie-handle 'cvs-dir-member-p + (cvs-fileinfo->dir (tin-cookie cvs-cookie-handle 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 (tin) + "Return non-nil if TIN is a directory that is empty. +Args: CVS-BUF TIN." + (and (eq (cvs-fileinfo->type (tin-cookie cvs-cookie-handle tin)) 'DIRCHANGE) + (or (not (tin-next cvs-cookie-handle tin)) + (eq (cvs-fileinfo->type + (tin-cookie cvs-cookie-handle + (tin-next cvs-cookie-handle tin))) + 'DIRCHANGE)))) + +(defun cvs-mode-revert-updated-buffers () + "Revert any buffers that are UPDATED, MERGED or CONFLICT." + (interactive) + (cookie-map (function cvs-revert-fileinfo) cvs-cookie-handle)) + +(defun cvs-revert-fileinfo (fileinfo) + "Revert the buffer that holds the file in FILEINFO if it has changed, +and if the type is UPDATED, MERGED or CONFLICT." + (let* ((type (cvs-fileinfo->type fileinfo)) + (file (cvs-fileinfo->full-path fileinfo)) + (buffer (get-file-buffer file))) + ;; For a revert to happen... + (cond + ((and + ;; ...the type must be one that justifies a revert... + (or (eq type 'UPDATED) + (eq type 'MERGED) + (eq type 'CONFLICT)) + ;; ...and the user must be editing the file... + buffer) + (save-excursion + (set-buffer buffer) + (cond + ((buffer-modified-p) + (error "%s: edited since last cvs-update." + (buffer-file-name))) + ;; Go ahead and revert the file. + (t (revert-buffer 'dont-use-auto-save-file 'dont-ask)))))))) + + +(defun cvs-mode-remove-handled () + "Remove all lines that are handled. +Empty directories are removed." + (interactive) + ;; Pass one: remove files that are handled. + (collection-filter-cookies cvs-cookie-handle + (function + (lambda (fileinfo) (not (cvs-fileinfo->handled fileinfo))))) + ;; Pass two: remove empty directories. + (cvs-remove-empty-directories)) + + +(defun cvs-remove-empty-directories () + "Remove empty directories in the *cvs* buffer." + (collection-filter-tins cvs-cookie-handle + (function + (lambda (tin) + (not (cvs-dir-empty-p tin)))))) + +(defun cvs-mode-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 (tin-locate cvs-cookie-handle pos)) + (sel (tin-cookie cvs-cookie-handle 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. + cvs-cookie-handle + (cvs-fileinfo->dir sel))) + (t + (cvs-set-fileinfo->marked sel t) + (tin-invalidate cvs-cookie-handle tin) + (tin-goto-next cvs-cookie-handle pos 1))))) + + +(defun cvs-committable (tin) + "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 (tin-cookie cvs-cookie-handle 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-mode-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)))) + (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) + (message "Press C-c C-c when you are done editing.")))) + + +(defun cvs-edit-done () + "Commit the files to the repository." + (interactive) + (if (null cvs-commit-list) + (error "You have already commited the files")) + (if (and (> (point-max) 1) + (/= (char-after (1- (point-max))) ?\n) + (or (eq cvs-commit-buffer-require-final-newline t) + (and cvs-commit-buffer-require-final-newline + (yes-or-no-p + (format "Buffer %s does not end in newline. Add one? " + (buffer-name)))))) + (save-excursion + (goto-char (point-max)) + (insert ?\n))) + (save-some-buffers) + (let ((cc-list cvs-commit-list) + (cc-buffer (get-buffer cvs-buffer-name)) + (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...") + (if (cvs-execute-list cc-list cvs-program + (if cvs-cvsroot + (list "-d" cvs-cvsroot "commit" "-m" msg) + (list "commit" "-m" msg))) + (error "Something went wrong. Check the %s buffer carefully." + cvs-temp-buffer-name)) + (let ((ccl cc-list)) + (while ccl + (cvs-after-commit-function (tin-cookie cvs-cookie-handle (car ccl))) + (setq ccl (cdr ccl)))) + (apply 'tin-invalidate cvs-cookie-handle cc-list) + (set-buffer msg-buffer) + (setq cvs-commit-list nil) + (set-buffer cc-buffer) + (if cvs-auto-remove-handled + (cvs-mode-remove-handled))) + + (message "Committing... Done.")) + +(defun cvs-after-commit-function (fileinfo) + "Do everything that needs to be done when FILEINFO has been commited. +The fileinfo->handle is set, and if the buffer is present it is reverted." + (cvs-set-fileinfo->handled fileinfo t) + (if cvs-auto-revert-after-commit + (let* ((file (cvs-fileinfo->full-path fileinfo)) + (buffer (get-file-buffer file))) + ;; For a revert to happen... + (if buffer + ;; ...the user must be editing the file... + (save-excursion + (set-buffer buffer) + (if (not (buffer-modified-p)) + ;; ...but it must be unmodified. + (revert-buffer 'dont-use-auto-save-file 'dont-ask))))))) + + +(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). + +Any output from PROGRAM will be inserted in the current buffer. + +This function return nil if all went well, or the numerical exit +status or a signal name as a string. Note that PROGRAM might be called +several times. This will return non-nil if something goes wrong, but +there is no way to know which process that failed." + + (let ((exitstatus nil)) + (while tin-list + (let ((current-dir (cvs-fileinfo->dir + (tin-cookie cvs-cookie-handle + (car tin-list)))) + arg-list arg-str) + + ;; Collect all marked files in this directory. + + (while (and tin-list + (string= + current-dir + (cvs-fileinfo->dir + (tin-cookie cvs-cookie-handle (car tin-list))))) + (setq arg-list + (cons (cvs-fileinfo->file-name + (tin-cookie cvs-cookie-handle (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) + " "))) + (let ((res (apply 'call-process program nil t t + (nconc (copy-sequence constant-args) arg-list)))) + ;; Remember the first, or highest, exitstatus. + (if (and (not (and (integerp res) (zerop res))) + (or (null exitstatus) + (and (integerp exitstatus) (= 1 exitstatus)))) + (setq exitstatus res))) + (goto-char (point-max)))) + exitstatus)) + + +(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 + (tin-cookie cvs-cookie-handle + (car tin-list))))) + (arg-list + (funcall extractor + (tin-cookie cvs-cookie-handle (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-diffable (tins) + "Return a list of all tins on TINS that it makes sense to run +``cvs diff'' on." + ;; +++ There is an unnecessary (nreverse) here. Get the list the + ;; other way around instead! + (let ((result nil)) + (while tins + (let ((type (cvs-fileinfo->type + (tin-cookie cvs-cookie-handle (car tins))))) + (if (or (eq type 'MODIFIED) + (eq type 'UPDATED) + (eq type 'MERGED) + (eq type 'CONFLICT) + (eq type 'REMOVED) ;+++Does this line make sense? + (eq type 'ADDED)) ;+++Does this line make sense? + (setq result (cons (car tins) result))) + (setq tins (cdr tins)))) + (nreverse result))) + + +(defun cvs-mode-diff-cvs (&optional ignore-marks) + "Diff the selected files against the repository. +The flags in the variable cvs-diff-flags (which should be a list +of strings) will be passed to ``cvs diff''. If the variable +cvs-diff-ignore-marks is non-nil any marked files will not be +considered to be selected. An optional prefix argument will invert +the influence from cvs-diff-ignore-marks." + + (interactive "P") + + (if (not (listp cvs-diff-flags)) + (error "cvs-diff-flags should be a list of strings")) + + (save-some-buffers) + (let ((marked (cvs-diffable + (cvs-get-marked + (or (and ignore-marks (not cvs-diff-ignore-marks)) + (and (not ignore-marks) cvs-diff-ignore-marks)))))) + (cvs-use-temp-buffer) + (message "cvsdiffing...") + ;; Don't care much about the exit status since it is the _sum_ of + ;; the status codes from the different files (not the _max_ as it + ;; should be). + (if (cvs-execute-list marked cvs-program + (if cvs-cvsroot + (cons "-d" (cons cvs-cvsroot + (cons "diff" cvs-diff-flags))) + (cons "diff" cvs-diff-flags))) + (message "cvsdiffing... Done.") + (message "cvsdiffing... No differences found.")))) + + +(defun cvs-backup-diffable (tin) + "Check if the TIN is backup-diffable. +It must have a backup file to be diffable." + (file-readable-p + (cvs-fileinfo->backup-file (tin-cookie cvs-cookie-handle tin)))) + +(defun cvs-mode-diff-backup (&optional ignore-marks) + "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. + +If the variable cvs-diff-ignore-marks is non-nil any marked files will +not be considered to be selected. An optional prefix argument will +invert the influence from cvs-diff-ignore-marks. + +The flags in cvs-diff-flags will be passed to ``diff''." + + (interactive "P") + + (if (not (listp cvs-diff-flags)) + (error "cvs-diff-flags should be a list of strings.")) + + (save-some-buffers) + (let ((marked (cvs-filter + (function cvs-backup-diffable) + (cvs-get-marked + (or + (and ignore-marks (not cvs-diff-ignore-marks)) + (and (not ignore-marks) cvs-diff-ignore-marks)))))) + (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 (not (file-readable-p (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->backup-file fileinfo) + (cvs-fileinfo->file-name fileinfo))) + +(defun cvs-mode-find-file-other-window (pos) + "Select a buffer containing the file in another window. +Args: POS" + (interactive "d") + (let ((tin (tin-locate cvs-cookie-handle pos))) + (if tin + (let ((type (cvs-fileinfo->type (tin-cookie cvs-cookie-handle + 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 + (tin-cookie cvs-cookie-handle tin)))) + (dired-other-window default-directory) + (set-buffer obuf) + (setq default-directory odir))) + (t + (find-file-other-window (cvs-full-path tin))))) + (error "There is no file to find.")))) + +(defun cvs-fileinfo->full-path (fileinfo) + "Return the full path for the file that is described in FILEINFO." + (concat + (file-name-as-directory + (cvs-fileinfo->dir fileinfo)) + (cvs-fileinfo->file-name fileinfo))) + +(defun cvs-full-path (tin) + "Return the full path for the file that is described in TIN." + (cvs-fileinfo->full-path (tin-cookie cvs-cookie-handle tin))) + +(defun cvs-mode-find-file (pos) + "Select a buffer containing the file in another window. +Args: POS" + (interactive "d") + (let* ((cvs-buf (current-buffer)) + (tin (tin-locate cvs-cookie-handle pos))) + (if tin + (let* ((fileinfo (tin-cookie cvs-cookie-handle 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 tin))))) + (error "There is no file to find.")))) + +(defun cvs-mode-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)))) + cvs-cookie-handle)) + + +(defun cvs-mode-unmark (pos) + "Unmark a fileinfo. Args: POS." + (interactive "d") + + (let* ((tin (tin-locate cvs-cookie-handle pos)) + (sel (tin-cookie cvs-cookie-handle 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)))) + cvs-cookie-handle + (cvs-fileinfo->dir sel))) + (t + (cvs-set-fileinfo->marked sel nil) + (tin-invalidate cvs-cookie-handle tin) + (tin-goto-next cvs-cookie-handle pos 1))))) + +(defun cvs-mode-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)) + cvs-cookie-handle)) + + +(defun cvs-do-removal (tins) + "Remove files. +Args: TINS. +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 (tin-cookie cvs-cookie-handle tin)) + (type (cvs-fileinfo->type fileinfo))) + (if (not (or (eq type 'REMOVED) (eq type 'CVS-REMOVED))) + (progn + (delete-file (cvs-full-path tin)) + (cond + ((or (eq type 'UNKNOWN) (eq type 'MOVE-AWAY)) + (tin-delete cvs-cookie-handle tin)) + (t + (setq files-to-remove (cons tin files-to-remove)) + (cvs-set-fileinfo->type fileinfo 'REMOVED) + (cvs-set-fileinfo->handled fileinfo nil) + (tin-invalidate cvs-cookie-handle tin)))))) + (setq tins (cdr tins))) + files-to-remove)) + (t nil))) + + + +(defun cvs-mode-remove-file () + "Remove all marked files." + (interactive) + (let ((files-to-remove (cvs-do-removal (cvs-get-marked)))) + (if (null files-to-remove) + nil + (cvs-use-temp-buffer) + (message "removing from repository...") + (if (cvs-execute-list files-to-remove cvs-program + (if cvs-cvsroot + (list "-d" cvs-cvsroot "remove") + '("remove"))) + (error "CVS exited with non-zero exit status.") + (message "removing from repository... done."))))) + +(defun cvs-mode-undo-local-changes () + "Undo local changes to all marked files. +The file is removed and `cvs update FILE' is run." + (interactive) + (let ((tins-to-undo (cvs-get-marked))) + (cvs-use-temp-buffer) + (mapcar 'cvs-insert-full-path tins-to-undo) + (cond + ((and tins-to-undo (yes-or-no-p (format "Undo changes to %d files? " + (length tins-to-undo)))) + (let (files-to-update) + (while tins-to-undo + (let* ((tin (car tins-to-undo)) + (fileinfo (tin-cookie cvs-cookie-handle tin)) + (type (cvs-fileinfo->type fileinfo))) + (cond + ((or + (eq type 'UPDATED) (eq type 'MODIFIED) (eq type 'MERGED) + (eq type 'CONFLICT) (eq type 'CVS-REMOVED) + (eq type 'REM-CONFLICT) (eq type 'MOVE-AWAY) + (eq type 'REMOVED)) + (if (not (eq type 'REMOVED)) + (delete-file (cvs-full-path tin))) + (setq files-to-update (cons tin files-to-update)) + (cvs-set-fileinfo->type fileinfo 'UPDATED) + (cvs-set-fileinfo->handled fileinfo t) + (tin-invalidate cvs-cookie-handle tin)) + + ((eq type 'MOD-CONFLICT) + (error "Use cvs-mode-add instead on %s." + (cvs-fileinfo->file-name fileinfo))) + + ((eq type 'REM-CONFLICT) + (error "Can't deal with a file you have removed and recreated.")) + + ((eq type 'DIRCHANGE) + (error "Undo on directories not supported (yet).")) + + ((eq type 'ADDED) + (error "There is no old revision to get for %s" + (cvs-fileinfo->file-name fileinfo))) + (t (error "cvs-mode-undo-local-changes: can't handle an %s" + type))) + + (setq tins-to-undo (cdr tins-to-undo)))) + (cvs-use-temp-buffer) + (message "Regetting files from repository...") + (if (cvs-execute-list files-to-update cvs-program + (if cvs-cvsroot + (list "-d" cvs-cvsroot "update") + '("update"))) + (error "CVS exited with non-zero exit status.") + (message "Regetting files from repository... done."))))))) + +(defun cvs-mode-acknowledge () + "Remove all marked files from the buffer." + (interactive) + + (mapcar (function (lambda (tin) + (tin-delete cvs-cookie-handle tin))) + (cvs-get-marked))) + + +(defun cvs-mode-unmark-up (pos) + "Unmark the file on the previous line. +Takes one argument POS, a buffer position." + (interactive "d") + (let ((tin (tin-goto-previous cvs-cookie-handle pos 1))) + (cond + (tin + (cvs-set-fileinfo->marked (tin-cookie cvs-cookie-handle tin) + nil) + (tin-invalidate cvs-cookie-handle tin))))) + +(defun cvs-mode-previous-line (arg) + "Go to the previous line. +If a prefix argument is given, move by that many lines." + (interactive "p") + (tin-goto-previous cvs-cookie-handle (point) arg)) + +(defun cvs-mode-next-line (arg) + "Go to the next line. +If a prefix argument is given, move by that many lines." + (interactive "p") + (tin-goto-next cvs-cookie-handle (point) arg)) + +(defun cvs-add-file-update-buffer (tin) + "Subfunction to cvs-mode-add. Internal use only. +Update the display. Return non-nil if `cvs add' should be called on this +file. Args: TIN. +Returns 'ADD or 'RESURRECT." + (let ((fileinfo (tin-cookie cvs-cookie-handle tin))) + (cond + ((eq (cvs-fileinfo->type fileinfo) 'UNKNOWN) + (cvs-set-fileinfo->type fileinfo 'ADDED) + (tin-invalidate cvs-cookie-handle tin) + 'ADD) + ((eq (cvs-fileinfo->type fileinfo) 'REMOVED) + (cvs-set-fileinfo->type fileinfo 'UPDATED) + (cvs-set-fileinfo->handled fileinfo t) + (tin-invalidate cvs-cookie-handle 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 (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-mode-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...") + (if (cvs-execute-list resurrect cvs-program + (if cvs-cvsroot + (list "-d" cvs-cvsroot "add") + '("add"))) + (error "CVS exited with non-zero exit status.") + (message "Done.")))) + + (cond (added + (message "Adding new files to repository...") + (if (cvs-execute-list added cvs-program + (if cvs-cvsroot + (list "-d" cvs-cvsroot "add" "-m" msg) + (list "add" "-m" msg))) + (error "CVS exited with non-zero exit status.") + (message "Done.")))))) + +(defun cvs-mode-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 + (tin-cookie cvs-cookie-handle tin)) + 'UNKNOWN) + (cvs-append-to-ignore + (tin-cookie cvs-cookie-handle tin)) + (tin-delete cvs-cookie-handle tin))))) + (cvs-get-marked))) + +(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") + (if cvs-sort-ignore-file + (sort-lines nil (point-min) (point-max))) + (save-buffer))) + +(defun cvs-mode-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 ...") + (if (cvs-execute-list + marked cvs-program + (if cvs-cvsroot + (cons "-d" (cons cvs-cvsroot (cons "status" cvs-status-flags))) + (cons "status" cvs-status-flags))) + (error "CVS exited with non-zero exit status.") + (message "Running cvs status ... Done.")))) + +(defun cvs-mode-log () + "Display the cvs log of all selected files." + (interactive) + + (let ((marked (cvs-get-marked))) + (cvs-use-temp-buffer) + (message "Running cvs log ...") + (if (cvs-execute-list marked cvs-program + (if cvs-cvsroot + (cons "-d" (cons cvs-cvsroot + (cons "log" cvs-log-flags))) + (cons "log" cvs-log-flags))) + (error "CVS exited with non-zero exit status.") + (message "Running cvs log ... Done.")))) + +(defun cvs-byte-compile-files () + "Run byte-compile-file on all selected files that end in '.el'." + (interactive) + (let ((marked (cvs-get-marked))) + (while marked + (let ((filename (cvs-full-path (car marked)))) + (if (string-match "\\.el$" filename) + (byte-compile-file filename))) + (setq marked (cdr marked))))) + +(defun cvs-insert-full-path (tin) + "Insert full path to the file described in TIN in the current buffer." + (insert (format "%s\n" (cvs-full-path tin)))) + + +(defun cvs-mode-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 + (tin-cookie + cvs-cookie-handle + (tin-locate cvs-cookie-handle pos))))) + (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 (tin-cookie cvs-cookie-handle 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))) + +(defun cvs-mode-emerge (pos) + "Emerge appropriate revisions of the selected file. +Args: POS" + (interactive "d") + (let* ((cvs-buf (current-buffer)) + (tin (tin-locate cvs-cookie-handle pos))) + (if tin + (let* ((fileinfo (tin-cookie cvs-cookie-handle tin)) + (type (cvs-fileinfo->type fileinfo))) + (cond + ((eq type 'MODIFIED) + (require 'emerge) + (let ((tmp-file + (cvs-retrieve-revision-to-tmpfile fileinfo))) + (unwind-protect + (if (not (emerge-files + t + (cvs-fileinfo->full-path fileinfo) + tmp-file + (cvs-fileinfo->full-path fileinfo))) + (error "Emerge session failed")) + (delete-file tmp-file)))) + + ((or (eq type 'MERGED) + (eq type 'CONFLICT)) + (require 'emerge) + (let ((tmp-file + (cvs-retrieve-revision-to-tmpfile + fileinfo)) + (ancestor-file + (cvs-retrieve-revision-to-tmpfile + fileinfo + (cvs-fileinfo->base-revision fileinfo)))) + (unwind-protect + (if (not (emerge-files-with-ancestor + t + (cvs-fileinfo->backup-file fileinfo) + tmp-file + ancestor-file + (cvs-fileinfo->full-path fileinfo))) + (error "Emerge session failed")) + (delete-file tmp-file) + (delete-file ancestor-file)))) + (t + (error "Can only emerge \"Modified\", \"Merged\" or \"Conflict\"%s" + " files")))) + (error "There is no file to emerge.")))) + +(defun cvs-retrieve-revision-to-tmpfile (fileinfo &optional revision) + "Retrieve the latest revision of the file in FILEINFO to a temporary file. +If second optional argument REVISION is given, retrieve that revision instead." + (let + ((temp-name (make-temp-name + (concat (file-name-as-directory + (or (getenv "TMPDIR") "/tmp")) + "pcl-cvs." revision)))) + (cvs-kill-buffer-visiting temp-name) + (if revision + (message "Retrieving revision %s..." revision) + (message "Retrieving latest revision...")) + (let ((res (call-process cvs-shell nil nil nil "-c" + (concat cvs-program " update -p " + (if revision + (concat "-r " revision " ") + "") + (cvs-fileinfo->full-path fileinfo) + " > " temp-name)))) + (if (and res (not (and (integerp res) (zerop res)))) + (error "Something went wrong: %s" res)) + + (if revision + (message "Retrieving revision %s... Done." revision) + (message "Retrieving latest revision... Done.")) + (find-file-noselect temp-name) + temp-name))) + +(defun cvs-fileinfo->backup-file (fileinfo) + "Construct the file name of the backup file for FILEINFO." + (if (cvs-fileinfo->base-revision fileinfo) + (concat cvs-bakprefix (cvs-fileinfo->file-name fileinfo) + "." (cvs-fileinfo->base-revision fileinfo)))) + +(defun cvs-kill-buffer-visiting (filename) + "If there is any buffer visiting FILENAME, kill it (without confirmation)." + (let ((l (buffer-list))) + (while l + (if (string= (buffer-file-name (car l)) filename) + (kill-buffer (car l))) + (setq l (cdr l))))) + +(defun cvs-change-cvsroot (newroot) + "Change the cvsroot." + (interactive "DNew repository: ") + (if (or (file-directory-p (expand-file-name "CVSROOT" newroot)) + (y-or-n-p (concat "Warning: no CVSROOT found inside repository." + " Change cvs-cvsroot anyhow?"))) + (setq cvs-cvsroot newroot))) + +(if (string-match "Lucid" emacs-version) + (progn + (autoload 'pcl-cvs-fontify "pcl-cvs-lucid") + (add-hook 'cvs-mode-hook 'pcl-cvs-fontify))) + + +(defvar cvs-changelog-full-paragraphs t + "If non-nil, include full ChangeLog paragraphs in the CVS log. +This may be set in the ``local variables'' section of a ChangeLog, to +indicate the policy for that ChangeLog. + +A ChangeLog paragraph is a bunch of log text containing no blank lines; +a paragraph usually describes a set of changes with a single purpose, +but perhaps spanning several functions in several files. Changes in +different paragraphs are unrelated. + +You could argue that the CVS log entry for a file should contain the +full ChangeLog paragraph mentioning the change to the file, even though +it may mention other files, because that gives you the full context you +need to understand the change. This is the behavior you get when this +variable is set to t. + +On the other hand, you could argue that the CVS log entry for a change +should contain only the text for the changes which occurred in that +file, because the CVS log is per-file. This is the behavior you get +when this variable is set to nil.") + +(defun cvs-changelog-name (directory) + "Return the name of the ChangeLog file that handles DIRECTORY. +This is in DIRECTORY or one of its parents. +Signal an error if we can't find an appropriate ChangeLog file." + (let ((dir (file-name-as-directory directory)) + file) + (while (and dir + (not (file-exists-p + (setq file (expand-file-name "ChangeLog" dir))))) + (let ((last dir)) + (setq dir (file-name-directory (directory-file-name dir))) + (if (equal last dir) + (setq dir nil)))) + (or dir + (error "Can't find ChangeLog for %s" directory)) + file)) + +(defun cvs-narrow-changelog () + "Narrow to the top page of the current buffer, a ChangeLog file. +Actually, the narrowed region doesn't include the date line. +A \"page\" in a ChangeLog file is the area between two dates." + (or (eq major-mode 'change-log-mode) + (error "cvs-narrow-changelog: current buffer isn't a ChangeLog")) + + (goto-char (point-min)) + + ;; Skip date line and subsequent blank lines. + (forward-line 1) + (if (looking-at "[ \t\n]*\n") + (goto-char (match-end 0))) + + (let ((start (point))) + (forward-page 1) + (narrow-to-region start (point)) + (goto-char (point-min)))) + +(defun cvs-changelog-paragraph () + "Return the bounds of the ChangeLog paragraph containing point. +If we are between paragraphs, return the previous paragraph." + (save-excursion + (beginning-of-line) + (if (looking-at "^[ \t]*$") + (skip-chars-backward " \t\n" (point-min))) + (list (progn + (if (re-search-backward "^[ \t]*\n" nil 'or-to-limit) + (goto-char (match-end 0))) + (point)) + (if (re-search-forward "^[ \t\n]*$" nil t) + (match-beginning 0) + (point))))) + +(defun cvs-changelog-subparagraph () + "Return the bounds of the ChangeLog subparagraph containing point. +A subparagraph is a block of non-blank lines beginning with an asterisk. +If we are between subparagraphs, return the previous subparagraph." + (save-excursion + (end-of-line) + (if (search-backward "*" nil t) + (list (progn (beginning-of-line) (point)) + (progn + (forward-line 1) + (if (re-search-forward "^[ \t]*[\n*]" nil t) + (match-beginning 0) + (point-max)))) + (list (point) (point))))) + +(defun cvs-changelog-entry () + "Return the bounds of the ChangeLog entry containing point. +The variable `cvs-changelog-full-paragraphs' decides whether an +\"entry\" is a paragraph or a subparagraph; see its documentation string +for more details." + (if cvs-changelog-full-paragraphs + (cvs-changelog-paragraph) + (cvs-changelog-subparagraph))) + +(defun cvs-changelog-ours-p () + "See if ChangeLog entry at point is for the current user, today. +Return non-nil iff it is." + ;; Code adapted from add-change-log-entry. + (looking-at (concat (regexp-quote (substring (current-time-string) + 0 10)) + ".* " + (regexp-quote (substring (current-time-string) -4)) + "[ \t]+" + (regexp-quote add-log-full-name) + " <" (regexp-quote add-log-mailing-address)))) + +(defun cvs-relative-path (base child) + "Return a directory path relative to BASE for CHILD. +If CHILD doesn't seem to be in a subdirectory of BASE, just return +the full path to CHILD." + (let ((base (file-name-as-directory (expand-file-name base))) + (child (expand-file-name child))) + (or (string= base (substring child 0 (length base))) + (error "cvs-relative-path: %s isn't in %s" child base)) + (substring child (length base)))) + +(defun cvs-changelog-entries (file) + "Return the ChangeLog entries for FILE, and the ChangeLog they came from. +The return value looks like this: + (LOGBUFFER (ENTRYSTART . ENTRYEND) ...) +where LOGBUFFER is the name of the ChangeLog buffer, and each +\(ENTRYSTART . ENTRYEND\) pair is a buffer region." + (save-excursion + (set-buffer (find-file-noselect + (cvs-changelog-name + (file-name-directory + (expand-file-name file))))) + (goto-char (point-min)) + (if (looking-at "[ \t\n]*\n") + (goto-char (match-end 0))) + (if (not (cvs-changelog-ours-p)) + (list (current-buffer)) + (save-restriction + (cvs-narrow-changelog) + (goto-char (point-min)) + + ;; Search for the name of FILE relative to the ChangeLog. If that + ;; doesn't occur anywhere, they're not using full relative + ;; filenames in the ChangeLog, so just look for FILE; we'll accept + ;; some false positives. + (let ((pattern (cvs-relative-path + (file-name-directory buffer-file-name) file))) + (if (or (string= pattern "") + (not (save-excursion + (search-forward pattern nil t)))) + (setq pattern file)) + + (let (texts) + (while (search-forward pattern nil t) + (let ((entry (cvs-changelog-entry))) + (setq texts (cons entry texts)) + (goto-char (elt entry 1)))) + + (cons (current-buffer) texts))))))) + +(defun cvs-changelog-insert-entries (buffer regions) + "Insert those regions in BUFFER specified in REGIONS. +Sort REGIONS front-to-back first." + (let ((regions (sort regions 'car-less-than-car)) + (last)) + (while regions + (if (and last (< last (car (car regions)))) + (newline)) + (setq last (elt (car regions) 1)) + (apply 'insert-buffer-substring buffer (car regions)) + (setq regions (cdr regions))))) + +(defun cvs-union (set1 set2) + "Return the union of SET1 and SET2, according to `equal'." + (while set2 + (or (member (car set2) set1) + (setq set1 (cons (car set2) set1))) + (setq set2 (cdr set2))) + set1) + +(defun cvs-insert-changelog-entries (files) + "Given a list of files FILES, insert the ChangeLog entries for them." + (let ((buffer-entries nil)) + + ;; Add each buffer to buffer-entries, and associate it with the list + ;; of entries we want from that file. + (while files + (let* ((entries (cvs-changelog-entries (car files))) + (pair (assq (car entries) buffer-entries))) + (if pair + (setcdr pair (cvs-union (cdr pair) (cdr entries))) + (setq buffer-entries (cons entries buffer-entries)))) + (setq files (cdr files))) + + ;; Now map over each buffer in buffer-entries, sort the entries for + ;; each buffer, and extract them as strings. + (while buffer-entries + (cvs-changelog-insert-entries (car (car buffer-entries)) + (cdr (car buffer-entries))) + (if (and (cdr buffer-entries) (cdr (car buffer-entries))) + (newline)) + (setq buffer-entries (cdr buffer-entries))))) + +(defun cvs-edit-delete-common-indentation () + "Unindent the current buffer rigidly until at least one line is flush left." + (save-excursion + (let ((common 100000)) + (goto-char (point-min)) + (while (< (point) (point-max)) + (if (not (looking-at "^[ \t]*$")) + (setq common (min common (current-indentation)))) + (forward-line 1)) + (indent-rigidly (point-min) (point-max) (- common))))) + +(defun cvs-mode-changelog-commit () + + "Check in all marked files, or the current file. +Ask the user for a log message in a buffer. + +This is just like `\\[cvs-mode-commit]', except that it tries to provide +appropriate default log messages by looking at the ChangeLogs. The +idea is to write your ChangeLog entries first, and then use this +command to commit your changes. + +To select default log text, we: +- find the ChangeLogs for the files to be checked in, +- verify that the top entry in the ChangeLog is on the current date + and by the current user; if not, we don't provide any default text, +- search the ChangeLog entry for paragraphs containing the names of + the files we're checking in, and finally +- use those paragraphs as the log text." + + (interactive) + + (let* ((cvs-buf (current-buffer)) + (marked (cvs-filter (function cvs-committable) + (cvs-get-marked)))) + (if (null marked) + (error "Nothing to commit!") + (pop-to-buffer (get-buffer-create cvs-commit-prompt-buffer)) + (goto-char (point-min)) + + (erase-buffer) + (cvs-insert-changelog-entries + (mapcar (lambda (tin) + (let ((cookie (tin-cookie cvs-cookie-handle tin))) + (expand-file-name + (cvs-fileinfo->file-name cookie) + (cvs-fileinfo->dir cookie)))) + marked)) + (cvs-edit-delete-common-indentation) + + (cvs-edit-mode) + (make-local-variable 'cvs-commit-list) + (setq cvs-commit-list marked) + (message "Press C-c C-c when you are done editing.")))) 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 00000000000..bbf572fda5f --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.info @@ -0,0 +1,66 @@ +This is Info file pcl-cvs.info, produced by Makeinfo-1.55 from the +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. + + +Indirect: +pcl-cvs.info-1: 1013 +pcl-cvs.info-2: 50562 + +Tag Table: +(Indirect) +Node: Top1013 +Node: Copying3575 +Node: Installation22813 +Node: Pcl-cvs installation23608 +Node: On-line manual installation25673 +Node: Typeset manual installation26696 +Node: About pcl-cvs27439 +Node: Contributors27813 +Node: Archives29121 +Node: Getting started29705 +Node: Buffer contents32146 +Node: File status32700 +Node: Selected files35730 +Node: Commands36403 +Node: Updating the directory37619 +Node: Movement commands39282 +Node: Marking files39873 +Node: Committing changes40735 +Node: Editing files42206 +Node: Getting info about files43056 +Node: Adding and removing files43541 +Node: Undoing changes44897 +Node: Removing handled entries45362 +Node: Ignoring files46285 +Node: Viewing differences46820 +Node: Emerge48134 +Node: Reverting your buffers49113 +Node: Miscellaneous commands49815 +Node: Customization50562 +Node: Future enhancements54248 +Node: Bugs58449 +Node: Function and Variable Index60235 +Node: Concept Index63033 +Node: Key Index69634 + +End Tag Table diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.info-1 b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.info-1 new file mode 100644 index 00000000000..a56b771d50f --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.info-1 @@ -0,0 +1,1195 @@ +This is Info file pcl-cvs.info, produced by Makeinfo-1.55 from the +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.info, 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.05 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. +* Bugs:: Bugs (known and unknown). +* 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 +* Undoing changes:: Undoing changes +* Removing handled entries:: Uninteresting lines can easily be removed. +* Ignoring files:: Telling CVS to ignore generated files. +* Viewing differences:: Commands to `diff' different versions. +* Emerge:: +* Reverting your buffers:: Reverting your buffers +* Miscellaneous commands:: Miscellaneous commands + + +File: pcl-cvs.info, 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: + + a. You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any + change. + + b. 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. + + c. 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: + + a. 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, + + b. 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, + + c. 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.info, 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.info, 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. Release 1.05 and later of pcl-cvs requires parts of the Elib + library, version 0.07 or later. Elib is available via anonymous + ftp from prep.ai.mit.edu in `pub/gnu/elib-0.07.tar.z', and from + a lot of other sites that mirrors prep. Get Elib, and install + it, before proceeding. + + 4. 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. + + 5. 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.info, 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.info, 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.info, 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.info, 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 Bugs::.). + + 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. + + * Jamie Zawinski (`jwz@lucid.com') contributed `pcl-cvs-lucid.el'. + + * Leif Lonnblad contributed RCVS support. + + Apart from these, a lot of people have send me suggestions, ideas, +requests, bug reports and encouragement. Thanks a lot! Without your +there would be no new releases of pcl-cvs. + + +File: pcl-cvs.info, Node: Archives, Prev: Contributors, Up: About pcl-cvs + +Where can I get pcl-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.info, 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 cvs-update 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.05. + + 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.info, 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.info, 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.info, 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.info, 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 +* Undoing changes:: Undoing changes +* Removing handled entries:: Uninteresting lines can easily be removed. +* Ignoring files:: Telling CVS to ignore generated files. +* Viewing differences:: Commands to `diff' different versions. +* Emerge:: +* Reverting your buffers:: Reverting your buffers +* Miscellaneous commands:: Miscellaneous commands + + +File: pcl-cvs.info, 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. + + CVS uses lock files in the repository to ensure the integrity of + the data files in the repository. They might be left behind + i.e. if a workstation crashes in the middle of a CVS operation. + CVS outputs a message when it is waiting for a lock file to go + away. Pcl-cvs will show the same message in the *cvs* buffer, + together with instructions for deleting the lock files. You + should normally not have to delete them manually -- just wait a + little while and the problem should fix itself. But if the lock + files doesn't disappear you can delete them with `M-x + cvs-delete-lock RET'. + +`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-mode-update-no-prompt'. + + +File: pcl-cvs.info, 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.info, 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-mode-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-mode-unmark'). + +`M' + Mark *all* files in the buffer (`cvs-mode-mark-all-files'). + +`ESC DEL' + Unmark *all* files (`cvs-mode-unmark-all-files'). + +`DEL' + Unmark the file on the previous line, and move point to that line + (`cvs-mode-unmark-up'). + + +File: pcl-cvs.info, 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-mode-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'). + + If you are editing the files in your emacs an automatic + `revert-buffer' will be performed. (If the file contains `$Id: pcl-cvs.info-1,v 1.1 1995/12/19 09:21:41 deraadt Exp $' + keywords `cvs commit' will write a new file with the new values + substituted. The auto-revert makes sure that you get them into + your buffer). The revert will not occur if you have modified + your buffer, or if `cvs-auto-revert-after-commit' is set to + `nil'. + + +File: pcl-cvs.info, 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-mode-find-file'). + +`o' + Like `f', but use another window + (`cvs-mode-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-mode-add-change-log-entry-other-window'). + + +File: pcl-cvs.info, 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-mode-log'). + +`s' + Run `cvs status' on all selected files, and show the result in a + temporary buffer (`cvs-mode-status'). + + +File: pcl-cvs.info, Node: Adding and removing files, Next: Undoing changes, 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-mode-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-mode-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-mode-commit', *note + Committing changes::.) to commit the removal. + + The command that is run is `cvs-mode-remove-file'. + + +File: pcl-cvs.info, Node: Undoing changes, Next: Removing handled entries, Prev: Adding and removing files, Up: Commands + +Undoing changes +=============== + +`U' + If you have modified a file, and for some reason decide that you + don't want to keep the changes, you can undo them with this + command. It works by removing your working copy of the file and + then getting the latest version from the repository + (`cvs-mode-undo-local-changes'. + + +File: pcl-cvs.info, Node: Removing handled entries, Next: Ignoring files, Prev: Undoing changes, 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-mode-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-mode-remove-handled' would not delete, but that you want to + delete (`cvs-mode-acknowledge'). + + +File: pcl-cvs.info, 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-mode-ignore'. + + +File: pcl-cvs.info, Node: Viewing differences, Next: Emerge, 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'. If CVS-DIFF-IGNORE-MARKS + is set to a non-`nil' value or if a prefix argument is given + (but not both) any marked files will not be considered to be + selected. (`cvs-mode-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'. + + If CVS-DIFF-IGNORE-MARKS is set to a non-`nil' value or if a + prefix argument is given (but not both) any marked files will + not be considered to be selected. (`cvs-mode-diff-backup'). + + +File: pcl-cvs.info, Node: Emerge, Next: Reverting your buffers, Prev: Viewing differences, Up: Commands + +Running emerge +============== + +`e' + Invoke `emerge' on one file. This command works slightly + different depending on the file status. + + `Modified' + Run `emerge-files' with your working file as file A, and + the latest revision in the repository as file B. + + `Merged' + `Conflict' + Run `emerge-files-with-ancestor' with your working file (as + it was prior to your invocation of `cvs-update') as file A, + the latest revision in the repository as file B, and the + revision that you based your local modifications on as + ancestor. + + *Note:* CVS has already performed a merge. The resulting file is + not used in any way if you use this command. If you use the `q' + command inside `emerge' (to successfully terminate the merge) the + file that CVS created will be overwritten. + + +File: pcl-cvs.info, Node: Reverting your buffers, Next: Miscellaneous commands, Prev: Emerge, Up: Commands + +Reverting your buffers +====================== + +`R' + If you are editing (or just viewing) a file in a buffer, and + that file is changed by CVS during a `cvs-update', all you have + to do is type `R' in the *cvs* buffer to read in the new + versions of the files. + + All files that are `Updated', `Merged' or in `Conflict' are + reverted from the disk. Any other files are ignored. Only files + that you were already editing are read. + + An error is signalled if you have modified the buffer since it + was last changed. (`cvs-mode-revert-updated-buffers'). + + +File: pcl-cvs.info, Node: Miscellaneous commands, Prev: Reverting your buffers, Up: Commands + +Miscellaneous commands +====================== + +`M-x cvs-byte-compile-files' + Byte compile all selected files that end in .el. + +`M-x cvs-delete-lock' + This command can be used in any buffer, and deletes the lock + files that the *cvs* buffer informs you about. You should + normally never have to use this command since CVS tries very + carefully to always remove the lock files itself. + + You can only use this command when a message in the *cvs* buffer + tells you so. You should wait a while before using this command + in case someone else is running a cvs command. + +`q' + Bury the *cvs* buffer. (`bury-buffer'). + diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.info-2 b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.info-2 new file mode 100644 index 00000000000..ef28caa179a --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.info-2 @@ -0,0 +1,449 @@ +This is Info file pcl-cvs.info, produced by Makeinfo-1.55 from the +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.info, 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 Bugs:: 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-diff-flags' + A list of strings to pass as arguments to the `cvs diff' and + `diff' programs. This is used by `cvs-mode-diff-cvs' and + `cvs-mode-diff-backup' (key `b', *note Viewing differences::.). + If you prefer the Unidiff format you could add this line to your + `.emacs' file: + + (setq cvs-diff-flags '("-u")) + +`cvs-diff-ignore-marks' + If this variable is non-`nil' or if a prefix argument is given + (but not both) to `cvs-mode-diff-cvs' or `cvs-mode-diff-backup' + marked files are not considered selected. + +`cvs-log-flags' + List of strings to send to `cvs log'. Used by `cvs-mode-log' + (key `l', *note Getting info about files::.). + +`cvs-status-flags' + List of strings to send to `cvs status'. Used by + `cvs-mode-status' (key `s', *note Getting info about files::.). + +`cvs-auto-remove-handled' + If this variable is set to any non-`nil' value + `cvs-mode-remove-handled' will be called every time you check in + files, after the check-in is ready. *Note Removing handled + entries::. + +`cvs-auto-revert-after-commit' + If this variable is set to any non-`nil' value any buffers you + have that visit a file that is committed will be automatically + reverted. This variable is default `t'. *Note Committing + changes::. + +`cvs-update-prog-output-skip-regexp' + The `-u' flag in the `modules' file can be used to run a command + whenever a `cvs update' is performed (see cvs(5)). This regexp + is used to search for the last line in that output. It is + normally set to `"$"'. That setting is only correct if the + command outputs nothing. Note that pcl-cvs will get very + confused if the command outputs *anything* to `stderr'. + +`cvs-cvsroot' + This variable can be set to override `CVSROOT'. It should be a + string. If it is set then everytime a cvs command is run it will + be called as `cvs -d CVS-CVSROOT...' This can be useful if your + site has several repositories. + +`TMPDIR' + Pcl-cvs uses this *environment variable* to decide where to put + the temporary files it needs. It defaults to `/tmp' if it is + not set. + +`cvs-commit-buffer-require-final-newline' + When you enter a log message in the `*cvs-commit-message*' buffer + pcl-cvs will normally automatically insert a trailing newline, + unless there already is one. This behavior can be controlled via + `cvs-commit-buffer-require-final-newline'. If it is `t' (the + default behavior), a newline will always be appended. If it is + `nil', newlines will never be appended. Any other value causes + pcl-cvs to ask the user whenever there is no trailing newline in + the commit message buffer. + +`cvs-sort-ignore-file' + If this variable is set to any non-`nil' value the `.cvsignore' + will always be sorted whenever you use `cvs-mode-ignore' to add + a file to it. This option is on by default. + + +File: pcl-cvs.info, Node: Future enhancements, Next: Bugs, Prev: Customization, Up: Top + +Future enhancements +******************* + + Pcl-cvs is still under development and needs a number of +enhancements to be called complete. Below is my current wish-list +for future releases of pcl-cvs. Please, let me know which of these +features you want most. They are listed below in approximately the +order that I currently think I will implement them in. + + * Rewritten parser code. There are many situations where pcl-cvs + will fail to recognize the output from CVS. The situation could + be greatly increased. + + * `cvs-status'. This will run `cvs status' in a directory and + produce a buffer that looks pretty much like the current *cvs* + buffer. That buffer will include information for all + version-controlled files. (There will be a simple keystroke to + remove all "uninteresting" files, that is, files that are + "Up-to-date"). In this new buffer you will be able to update a + file, commit a file, et c. The big win with this is that you + will be able to watch the differences between your current + working file and the head revision in the repository before you + update the file, and you can then choose to update it or let it + wait for a while longer. + + * Log mode. When this mode is finished you will be able to move + around (using `n' and `p') between the revisions of a file, mark + two of them, and run a diff between them. You will be able to + hide branches (similar to the way you can hide sub-paragraphs in + outline-mode) and do merges between revisions. Other ideas + about this are welcome. + + * The current model for marks in the *cvs* buffer seems to be + confusing. I am considering to use the VM model instead, where + marks are normally inactive. To activate the mark, you issue a + command like `cvs-mode-next-command-uses-marks'. I might + implement a flag so that you can use either version. Feedback + on this before I start coding it is very welcome. + + * 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. I planed to put these kind of + commands on the prefix `C-c C-v', but that turned out to be used + by for instance c++-mode. If you have any suggestions for a + better prefix key, please let me know. + + * Increased robustness. For instance, you can not currently press + `C-g' when you are entering the description of a file that you + are adding without confusing pcl-cvs. + + * Support for multiple active *cvs* buffers. + + * 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. + + * An ability to send user-supplied options to all the cvs commands. + + * Pcl-cvs is not at all clever about what it should do when `cvs + update' runs a program (due to the `-u' option in the `modules' + file -- see `cvs(5)'). The current release uses a regexp to + search for the end. At the very least that regexp should be + configured for different modules. Tell me if you have any idea + about what is the right thing to do. In a perfect world the + program should also be allowed to print to `stderr' without + causing pcl-cvs to crash. + + 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 +Bugs:: for information about how to reach me. + + So far, I have written most of pcl-cvs in my all-to-rare spare +time. If you want pcl-cvs to be developed faster you can write a +contract with Signum Support to do the extension. You can reach +Signum Support by email to `info@signum.se' or via mail to Signum +Support AB, Box 2044, S-580 02 Linkoping, Sweden. Phone: +46 (0) 13 - +21 46 00. Fax: +46 (0) 13 - 21 47 00. + + +File: pcl-cvs.info, Node: Bugs, Next: Function and Variable Index, Prev: Future enhancements, Up: Top + +Bugs (known and unknown) +************************ + + 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! + + Below is a partial list of currently known problems with pcl-cvs +version 1.05. + +Commit causes Emacs to hang + Emacs waits for the `cvs commit' command to finish before you can + do anything. If you start a background job from the loginfo + file you must take care that it closes `stdout' and `stderr' if + you do not want to wait for it. (You do that with + `background-command &>- 2&>- &' if you are starting + `background-command' from a `/bin/sh' shell script). + + Your emacs will also hang if there was a lock file in the + repository. In this case you can type `C-g' to get control over + your emacs again. + +Name clash in Emacs 19 + This is really a bug in Elib or the Emacs 19 distribution. Both + Elib and Emacs 19.6 through at least 19.10 contains a file named + `cookie.el'. One of the files will have to be renamed, and we + are currently negotiating about which of the files to rename. + +Commands while cvs-update is running + It is possible to type commands in the *cvs* buffer while the + update is running, but error messages is all that you will get. + The error messages should be better. + +Unexpected output from CVS + Unexpected output from CVS confuses pcl-cvs. It will currently + create a bug report that you can mail to me. It should do + something more civilized. + + +File: pcl-cvs.info, Node: Function and Variable Index, Next: Concept Index, Prev: Bugs, Up: Top + +Function and Variable Index +*************************** + +* Menu: + +* bury-buffer: Miscellaneous commands. +* cookie-next-cookie: Movement commands. +* cookie-previous-cookie: Movement commands. +* cvs-auto-remove-handled (variable): Customization. +* cvs-auto-revert-after-commit (variable): Customization. +* cvs-auto-revert-after-commit (variable): Committing changes. +* cvs-byte-compile-files: Miscellaneous commands. +* cvs-commit-buffer-require-final-newline (variable): Customization. +* cvs-cvsroot (variable): Customization. +* cvs-delete-lock: Updating the directory. +* cvs-diff-flags (variable): Customization. +* cvs-diff-ignore-marks (variable): Customization. +* cvs-diff-ignore-marks (variable): Viewing differences. +* cvs-erase-input-buffer (variable): Customization. +* cvs-erase-input-buffer (variable): Committing changes. +* cvs-inhibit-copyright-message (variable): Customization. +* cvs-log-flags (variable): Customization. +* cvs-mode-acknowledge: Removing handled entries. +* cvs-mode-add: Adding and removing files. +* cvs-mode-add-change-log-entry-other-window: Editing files. +* cvs-mode-commit: Committing changes. +* cvs-mode-diff-backup: Viewing differences. +* cvs-mode-diff-cvs: Viewing differences. +* cvs-mode-emerge: Emerge. +* cvs-mode-find-file: Editing files. +* cvs-mode-find-file-other-window: Editing files. +* cvs-mode-ignore: Removing handled entries. +* cvs-mode-log: Getting info about files. +* cvs-mode-mark: Marking files. +* cvs-mode-mark-all-files: Marking files. +* cvs-mode-remove-file: Adding and removing files. +* cvs-mode-remove-handled: Removing handled entries. +* cvs-mode-revert-updated-buffers: Reverting your buffers. +* cvs-mode-status: Getting info about files. +* cvs-mode-undo-local-changes: Undoing changes. +* cvs-mode-unmark: Marking files. +* cvs-mode-unmark-all-files: Marking files. +* cvs-mode-unmark-up: Marking files. +* cvs-mode-update-no-prompt: Updating the directory. +* cvs-sort-ignore-file (variable): Customization. +* cvs-status-flags (variable): Customization. +* cvs-update: Updating the directory. +* cvs-update-prog-output-skip-regexp (variable): Customization. +* TMPDIR (environment variable): Customization. + + +File: pcl-cvs.info, Node: Concept Index, Next: Key Index, Prev: Function and Variable Index, Up: Top + +Concept Index +************* + +* Menu: + +* -u option in modules file: Customization. +* .cvsignore file, sorting: Customization. +* 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: Bugs. +* Authors: Contributors. +* Automatically inserting newline: Customization. +* Automatically remove handled files: Customization. +* Automatically sorting .cvsignore: Customization. +* Buffer contents: Buffer contents. +* Bugs, how to report them: Bugs. +* Bugs, known: Bugs. +* Byte compilation: Miscellaneous commands. +* Ci: Committing changes. +* Commit buffer: Committing changes. +* Commit message, inserting newline: Customization. +* Committing changes: Committing changes. +* Conflict (file status): File status. +* Conflicts, how to resolve them: Viewing differences. +* Conflicts, resolving: Emerge. +* 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: Bugs. +* Emerge: Emerge. +* Enhancements: Future enhancements. +* Erasing commit message: Committing changes. +* Erasing the input buffer: Customization. +* Example run: Getting started. +* Expunging uninteresting entries: Removing handled entries. +* FAQ: Bugs. +* File selection: Selected files. +* File status: File status. +* Finding files: Editing files. +* Flush changes: Undoing changes. +* 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 lock files: Miscellaneous commands. +* Getting rid of the Copyright message.: Customization. +* Getting rid of uninteresting lines: Removing handled entries. +* Getting status: Getting info about files. +* Getting the *cvs* buffer: Updating the directory. +* 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. +* Invoking emerge: Emerge. +* Known bugs: Bugs. +* Loading files: Editing files. +* Lock files: Miscellaneous commands. +* 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. +* Modules file (-u option): Customization. +* 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. +* Problems, list of common: Bugs. +* Putting files under CVS control: Adding and removing files. +* Recompiling elisp files: Miscellaneous commands. +* 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: Bugs. +* Require final newline: Customization. +* Resolving conflicts: Emerge. +* Resurrecting files: Adding and removing files. +* Reverting buffers: Reverting your buffers. +* Reverting buffers after commit: Committing changes. +* Reverting buffers after commit: Customization. +* Selected files: Selected files. +* Selecting files (commands to mark files): Marking files. +* Sites: Archives. +* Sorting the .cvsignore file: Customization. +* Status (cvs command): Getting info about files. +* Syncing buffers: Reverting your buffers. +* TeX - generating a typeset manual: Typeset manual installation. +* This repository is missing!... (file status): File status. +* Undo changes: Undoing changes. +* Unidiff, how to get: Customization. +* Uninteresting entries, getting rid of them: Removing handled entries. +* Unknown (file status): File status. +* Update program (-u option in modules file): Customization. +* Updated (file status): File status. +* Variables, list of all: Customization. +* Viewing differences: Viewing differences. + + +File: pcl-cvs.info, Node: Key Index, Prev: Concept Index, Up: Top + +Key Index +********* + +* Menu: + +* a - add a file: Adding and removing files. +* A - add ChangeLog entry: Editing files. +* b - diff backup file: Viewing differences. +* c - commit files: Committing changes. +* C-k - remove selected entries: Removing handled entries. +* C-n - Move down one file: Movement commands. +* C-p - Move up one file: Movement commands. +* d - run cvs diff: Viewing differences. +* DEL - unmark previous file: Marking files. +* e - invoke emerge: Emerge. +* ESC DEL - unmark all files: Marking files. +* 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. +* M - marking all files: Marking files. +* n - Move down one file: Movement commands. +* o - find file in other window: Editing files. +* p - Move up on file: Movement commands. +* q - bury the *cvs* buffer: Miscellaneous commands. +* r - remove a file: Adding and removing files. +* R - revert buffers: Reverting your buffers. +* s - run cvs status: Getting info about files. +* SPC - Move down one file: Movement commands. +* U - undo changes: Undoing changes. +* u - unmark a file: Marking files. +* x - remove processed entries: Removing handled entries. + + 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 00000000000..bb0a4fec3d8 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.texinfo @@ -0,0 +1,1744 @@ +\input texinfo @c -*-texinfo-*- + +@comment Id: pcl-cvs.texinfo,v 1.45 1993/05/31 22:38:15 ceder 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.info +@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.05 +@comment -release- +@sp 3 +@center Per Cederqvist +@sp 3 +@center last updated 31 May 1993 +@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.05 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. +* Bugs:: Bugs (known and unknown). +* 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 +* Undoing changes:: Undoing changes +* 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. +* Emerge:: +* Reverting your buffers:: Reverting your buffers +* Miscellaneous commands:: Miscellaneous commands +@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 +Release 1.05 and later of pcl-cvs requires parts of the Elib library, +version 0.07 or later. Elib is available via anonymous ftp from +prep.ai.mit.edu in @file{pub/gnu/elib-0.07.tar.z}, and from a lot of +other sites that mirrors prep. Get Elib, and install it, before +proceeding. + +@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{Bugs}). + +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 + +@item +Jamie Zawinski (@samp{jwz@@lucid.com}) contributed +@file{pcl-cvs-lucid.el}. + +@item +Leif Lonnblad contributed RCVS support. +@end itemize + +Apart from these, a lot of people have send me suggestions, ideas, +requests, bug reports and encouragement. Thanks a lot! Without your +there would be no new releases of pcl-cvs. + +@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 + +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 cvs-update 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.05. +@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 +* Undoing changes:: Undoing changes +* 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. +* Emerge:: +* Reverting your buffers:: Reverting your buffers +* Miscellaneous commands:: Miscellaneous commands +@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-mode-update-no-prompt +@findex cvs-delete-lock +@cindex Getting the *cvs* buffer +@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 + +CVS uses lock files in the repository to ensure the integrity of the +data files in the repository. They might be left behind i.e. if a +workstation crashes in the middle of a CVS operation. CVS outputs a +message when it is waiting for a lock file to go away. Pcl-cvs will +show the same message in the *cvs* buffer, together with instructions +for deleting the lock files. You should normally not have to delete +them manually --- just wait a little while and the problem should fix +itself. But if the lock files doesn't disappear you can delete them +with @kbd{M-x cvs-delete-lock RET}.@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-mode-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 ESC DEL - unmark all files +@kindex DEL - unmark previous file +@findex cvs-mode-mark +@findex cvs-mode-unmark +@findex cvs-mode-mark-all-files +@findex cvs-mode-unmark-all-files +@findex cvs-mode-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-mode-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-mode-unmark}).@refill + +@item M +Mark @emph{all} files in the buffer (@code{cvs-mode-mark-all-files}). + +@item @key{ESC} @key{DEL} +Unmark @emph{all} files (@code{cvs-mode-unmark-all-files}). + +@item @key{DEL} +Unmark the file on the previous line, and move point to that line +(@code{cvs-mode-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-mode-commit +@kindex c - commit files +@vindex cvs-erase-input-buffer (variable) +@vindex cvs-auto-revert-after-commit (variable) +@cindex Commit buffer +@cindex Edit buffer +@cindex Erasing commit message +@cindex Reverting buffers after commit + +@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-mode-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-@code{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 + +If you are editing the files in your emacs an automatic +@samp{revert-buffer} will be performed. (If the file contains +@samp{$@asis{Id}$} keywords @samp{cvs commit} will write a new file with +the new values substituted. The auto-revert makes sure that you get +them into your buffer). The revert will not occur if you have modified +your buffer, or if @samp{cvs-auto-revert-after-commit} is set to +@samp{nil}.@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-mode-find-file +@findex cvs-mode-find-file-other-window +@findex cvs-mode-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-mode-find-file}).@refill + +@item o +Like @kbd{f}, but use another window +(@code{cvs-mode-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-mode-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-mode-log +@findex cvs-mode-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-mode-log}). + +@item s +Run @samp{cvs status} on all selected files, and show the result in a +temporary buffer (@code{cvs-mode-status}). +@end table + +@node Adding and removing files, Undoing changes, 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-mode-add +@findex cvs-mode-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-mode-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-mode-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-mode-commit}, +@pxref{Committing changes}) to commit the removal.@refill + +The command that is run is @code{cvs-mode-remove-file}. +@end table + +@node Undoing changes, Removing handled entries, Adding and removing files, Commands +@comment node-name, next, previous, up +@section Undoing changes +@cindex Undo changes +@cindex Flush changes +@kindex U - undo changes +@findex cvs-mode-undo-local-changes + +@table @kbd +@item U +If you have modified a file, and for some reason decide that you don't +want to keep the changes, you can undo them with this command. It works +by removing your working copy of the file and then getting the latest +version from the repository (@code{cvs-mode-undo-local-changes}. +@end table + +@node Removing handled entries, Ignoring files, Undoing changes, 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-mode-remove-handled +@findex cvs-mode-acknowledge +@findex cvs-mode-ignore + +@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-mode-remove-handled}. If +@samp{cvs-auto-remove-handled} is set to non-@code{nil} this will +automatically be performed after every commit.@refill + +@item C-k +This command can be used for lines that @samp{cvs-mode-remove-handled} would +not delete, but that you want to delete (@code{cvs-mode-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-mode-ignore}. +@end table + +@node Viewing differences, Emerge, 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-mode-diff-cvs +@findex cvs-mode-diff-backup +@vindex cvs-diff-ignore-marks (variable) + +@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}. If @var{cvs-diff-ignore-marks} is set to a +non-@code{nil} value or if a prefix argument is given (but not both) any +marked files will not be considered to be selected. +(@code{cvs-mode-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.@refill + +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}.@refill + +If @var{cvs-diff-ignore-marks} is set to a non-@code{nil} value or if a +prefix argument is given (but not both) any marked files will not be +considered to be selected. (@code{cvs-mode-diff-backup}).@refill +@end table + +@node Emerge, Reverting your buffers, Viewing differences, Commands +@comment node-name, next, previous, up +@section Running emerge +@cindex Emerge +@cindex Invoking emerge +@cindex Conflicts, resolving +@cindex Resolving conflicts +@kindex e - invoke @samp{emerge} +@findex cvs-mode-emerge + +@table @kbd +@item e +Invoke @samp{emerge} on one file. This command works slightly different +depending on the file status. + +@table @asis +@item @samp{Modified} +Run @samp{emerge-files} with your working file as file A, and the latest +revision in the repository as file B. + +@item @samp{Merged} +@itemx @samp{Conflict} +Run @samp{emerge-files-with-ancestor} with your working file (as it was +prior to your invocation of @samp{cvs-update}) as file A, the latest +revision in the repository as file B, and the revision that you based +your local modifications on as ancestor. +@end table + +@strong{Note:} CVS has already performed a merge. The resulting file is +not used in any way if you use this command. If you use the @kbd{q} +command inside @samp{emerge} (to successfully terminate the merge) the +file that CVS created will be overwritten. +@end table + +@node Reverting your buffers, Miscellaneous commands, Emerge, Commands +@comment node-name, next, previous, up +@section Reverting your buffers +@findex cvs-mode-revert-updated-buffers +@kindex R - revert buffers +@cindex Syncing buffers +@cindex Reverting buffers + +@table @kbd +@item R +If you are editing (or just viewing) a file in a buffer, and that file +is changed by CVS during a @samp{cvs-update}, all you have to do is type +@kbd{R} in the *cvs* buffer to read in the new versions of the +files.@refill + +All files that are @samp{Updated}, @samp{Merged} or in @samp{Conflict} +are reverted from the disk. Any other files are ignored. Only files +that you were already editing are read.@refill + +An error is signalled if you have modified the buffer since it was last +changed. (@code{cvs-mode-revert-updated-buffers}).@refill +@end table + +@node Miscellaneous commands, , Reverting your buffers, Commands +@comment node-name, next, previous, up +@section Miscellaneous commands +@findex cvs-byte-compile-files +@cindex Recompiling elisp files +@cindex Byte compilation +@cindex Getting rid of lock files +@cindex Lock files +@kindex q - bury the *cvs* buffer +@findex bury-buffer + +@table @kbd +@item M-x cvs-byte-compile-files +Byte compile all selected files that end in .el. + +@item M-x cvs-delete-lock +This command can be used in any buffer, and deletes the lock files that +the *cvs* buffer informs you about. You should normally never have to +use this command since CVS tries very carefully to always remove the +lock files itself. + +You can only use this command when a message in the *cvs* buffer tells +you so. You should wait a while before using this command in case +someone else is running a cvs command. + +@item q +Bury the *cvs* buffer. (@code{bury-buffer}). + +@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-diff-flags (variable) +@vindex cvs-diff-ignore-marks (variable) +@vindex cvs-log-flags (variable) +@vindex cvs-status-flags (variable) +@vindex cvs-auto-remove-handled (variable) +@vindex cvs-update-prog-output-skip-regexp (variable) +@vindex cvs-cvsroot (variable) +@vindex TMPDIR (environment variable) +@vindex cvs-auto-revert-after-commit (variable) +@vindex cvs-commit-buffer-require-final-newline (variable) +@vindex cvs-sort-ignore-file (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 +@cindex -u option in modules file +@cindex Modules file (-u option) +@cindex Update program (-u option in modules file) +@cindex Reverting buffers after commit +@cindex Require final newline +@cindex Automatically inserting newline +@cindex Commit message, inserting newline +@cindex Sorting the .cvsignore file +@cindex .cvsignore file, sorting +@cindex Automatically sorting .cvsignore + +If you have an idea about any customization that would be handy but +isn't present in this list, please tell me! @xref{Bugs} for info on how +to reach me.@refill + +@table @samp +@item cvs-erase-input-buffer +If set to anything else than @code{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-diff-flags +A list of strings to pass as arguments to the @samp{cvs diff} and +@samp{diff} programs. This is used by @samp{cvs-mode-diff-cvs} and +@samp{cvs-mode-diff-backup} (key @kbd{b}, @pxref{Viewing differences}). If +you prefer the Unidiff format you could add this line to your +@file{.emacs} file:@refill + +@example +(setq cvs-diff-flags '("-u")) +@end example + +@item cvs-diff-ignore-marks +If this variable is non-@code{nil} or if a prefix argument is given (but +not both) to @samp{cvs-mode-diff-cvs} or @samp{cvs-mode-diff-backup} +marked files are not considered selected. + +@item cvs-log-flags +List of strings to send to @samp{cvs log}. Used by @samp{cvs-mode-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-mode-status} +(key @kbd{s}, @pxref{Getting info about files}). + +@item cvs-auto-remove-handled +If this variable is set to any non-@code{nil} value +@samp{cvs-mode-remove-handled} will be called every time you check in +files, after the check-in is ready. @xref{Removing handled +entries}.@refill + +@item cvs-auto-revert-after-commit +If this variable is set to any non-@samp{nil} value any buffers you have +that visit a file that is committed will be automatically reverted. +This variable is default @samp{t}. @xref{Committing changes}.@refill + +@item cvs-update-prog-output-skip-regexp +The @samp{-u} flag in the @file{modules} file can be used to run a command +whenever a @samp{cvs update} is performed (see cvs(5)). This regexp +is used to search for the last line in that output. It is normally set +to @samp{"$"}. That setting is only correct if the command outputs +nothing. Note that pcl-cvs will get very confused if the command +outputs @emph{anything} to @samp{stderr}. + +@item cvs-cvsroot +This variable can be set to override @samp{CVSROOT}. It should be a +string. If it is set then everytime a cvs command is run it will be +called as @samp{cvs -d @var{cvs-cvsroot}@dots{}} This can be useful if +your site has several repositories. + +@item TMPDIR +Pcl-cvs uses this @emph{environment variable} to decide where to put the +temporary files it needs. It defaults to @file{/tmp} if it is not set. + +@item cvs-commit-buffer-require-final-newline +When you enter a log message in the @samp{*cvs-commit-message*} buffer +pcl-cvs will normally automatically insert a trailing newline, unless +there already is one. This behavior can be controlled via +@samp{cvs-commit-buffer-require-final-newline}. If it is @samp{t} (the +default behavior), a newline will always be appended. If it is +@samp{nil}, newlines will never be appended. Any other value causes +pcl-cvs to ask the user whenever there is no trailing newline in the +commit message buffer. + +@item cvs-sort-ignore-file +If this variable is set to any non-@samp{nil} value the +@file{.cvsignore} will always be sorted whenever you use +@samp{cvs-mode-ignore} to add a file to it. This option is on by +default. + +@end table +@node Future enhancements, Bugs, 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. Below is my current wish-list for future releases +of pcl-cvs. Please, let me know which of these features you want most. +They are listed below in approximately the order that I currently think +I will implement them in. + +@itemize @bullet +@item +Rewritten parser code. There are many situations where pcl-cvs will +fail to recognize the output from CVS. The situation could be greatly +increased. + +@item +@samp{cvs-status}. This will run @samp{cvs status} in a directory and +produce a buffer that looks pretty much like the current *cvs* buffer. +That buffer will include information for all version-controlled files. +(There will be a simple keystroke to remove all "uninteresting" files, +that is, files that are "Up-to-date"). In this new buffer you will be +able to update a file, commit a file, et c. The big win with this is +that you will be able to watch the differences between your current +working file and the head revision in the repository before you update +the file, and you can then choose to update it or let it wait for a +while longer. + +@item +Log mode. When this mode is finished you will be able to move around +(using @kbd{n} and @kbd{p}) between the revisions of a file, mark two of +them, and run a diff between them. You will be able to hide branches +(similar to the way you can hide sub-paragraphs in outline-mode) and do +merges between revisions. Other ideas about this are welcome. + +@item +The current model for marks in the *cvs* buffer seems to be confusing. +I am considering to use the VM model instead, where marks are normally +inactive. To activate the mark, you issue a command like +@samp{cvs-mode-next-command-uses-marks}. I might implement a flag so +that you can use either version. Feedback on this before I start coding +it is very welcome. + +@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. I planed to put these kind of commands on the prefix +@kbd{C-c C-v}, but that turned out to be used by for instance c++-mode. +If you have any suggestions for a better prefix key, please let me know. + +@item +Increased robustness. For instance, you can not currently press +@kbd{C-g} when you are entering the description of a file that you are +adding without confusing pcl-cvs. + +@item +Support for multiple active *cvs* buffers. + +@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 +An ability to send user-supplied options to all the cvs commands. + +@item +Pcl-cvs is not at all clever about what it should do when @samp{cvs +update} runs a program (due to the @samp{-u} option in the +@file{modules} file --- see @samp{cvs(5)}). The current release uses a +regexp to search for the end. At the very least that regexp should be +configured for different modules. Tell me if you have any idea about +what is the right thing to do. In a perfect world the program should +also be allowed to print to @samp{stderr} without causing pcl-cvs to +crash. +@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{Bugs} for +information about how to reach me.@refill + +So far, I have written most of pcl-cvs in my all-to-rare spare time. If +you want pcl-cvs to be developed faster you can write a contract with +Signum Support to do the extension. You can reach Signum Support by +email to @samp{info@@signum.se} or via mail to Signum Support AB, Box +2044, S-580 02 Linkoping, Sweden. Phone: +46 (0) 13 - 21 46 00. Fax: +46 +(0) 13 - 21 47 00. + +@node Bugs, Function and Variable Index, Future enhancements, Top +@comment node-name, next, previous, up +@chapter Bugs (known and unknown) +@cindex Reporting bugs and ideas +@cindex Bugs, how to report them +@cindex Author, how to reach +@cindex Email to the author +@cindex Known bugs +@cindex Bugs, known +@cindex FAQ +@cindex Problems, list of common + +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! + +Below is a partial list of currently known problems with pcl-cvs version +1.05. + +@table @asis +@item Commit causes Emacs to hang +Emacs waits for the @samp{cvs commit} command to finish before you can +do anything. If you start a background job from the loginfo file you +must take care that it closes @samp{stdout} and @samp{stderr} if you do +not want to wait for it. (You do that with @samp{background-command &>- +2&>- &} if you are starting @samp{background-command} from a +@samp{/bin/sh} shell script). + +Your emacs will also hang if there was a lock file in the repository. +In this case you can type @kbd{C-g} to get control over your emacs +again. + +@item Name clash in Emacs 19 +This is really a bug in Elib or the Emacs 19 distribution. Both Elib and +Emacs 19.6 through at least 19.10 contains a file named +@file{cookie.el}. One of the files will have to be renamed, and we are +currently negotiating about which of the files to rename. + +@item Commands while cvs-update is running +It is possible to type commands in the *cvs* buffer while the update is +running, but error messages is all that you will get. The error +messages should be better. + +@item Unexpected output from CVS +Unexpected output from CVS confuses pcl-cvs. It will currently create a +bug report that you can mail to me. It should do something more +civilized. +@end table + +@node Function and Variable Index, Concept Index, Bugs, 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 00000000000..de11a7ffca0 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/texinfo.tex @@ -0,0 +1,4381 @@ +%% TeX macros to handle texinfo files + +% Copyright (C) 1985, 86, 88, 90, 91, 92, 93, 1994 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! + +% This automatically updates the version number based on RCS. +\def\deftexinfoversion$#1: #2 ${\def\texinfoversion{#2}} +\deftexinfoversion$fixed-revision: 2.137 $ +\message{Loading texinfo package [Version \texinfoversion]:} + +% 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\ptextilde=\~ +\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 + +% Be sure we're in horizontal mode when doing a tie, since we make space +% equivalent to this in @example-like environments. Otherwise, a space +% at the beginning of a line will start with \penalty -- and +% since \penalty is valid in vertical mode, we'd end up putting the +% penalty on the vertical list instead of in the new paragraph. +{\catcode`@ = 11 + \gdef\tie{\leavevmode\penalty\@M\ } +} +\let\~ = \tie % And make it available as @~. + +\message{Basics,} +\chardef\other=12 + +% If this character appears in an error message or help string, it +% starts a new line in the output. +\newlinechar = `^^J + +% Set up fixed words for English. +\ifx\putwordChapter\undefined{\gdef\putwordChapter{Chapter}}\fi% +\def\putwordInfo{Info}% +\ifx\putwordSee\undefined{\gdef\putwordSee{See}}\fi% +\ifx\putwordsee\undefined{\gdef\putwordsee{see}}\fi% +\ifx\putwordfile\undefined{\gdef\putwordfile{file}}\fi% +\ifx\putwordpage\undefined{\gdef\putwordpage{page}}\fi% +\ifx\putwordsection\undefined{\gdef\putwordsection{section}}\fi% +\ifx\putwordSection\undefined{\gdef\putwordSection{Section}}\fi% +\ifx\putwordTableofContents\undefined{\gdef\putwordTableofContents{Table of Contents}}\fi% +\ifx\putwordShortContents\undefined{\gdef\putwordShortContents{Short Contents}}\fi% +\ifx\putwordAppendix\undefined{\gdef\putwordAppendix{Appendix}}\fi% + +% Ignore a token. +% +\def\gobble#1{} + +\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 + +% Sometimes it is convenient to have everything in the transcript file +% and nothing on the terminal. We don't just call \tracingall here, +% since that produces some useless output on the terminal. +% +\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% +\def\loggingall{\tracingcommands2 \tracingstats2 + \tracingpages1 \tracingoutput1 \tracinglostchars1 + \tracingmacros2 \tracingparagraphs1 \tracingrestores1 + \showboxbreadth\maxdimen\showboxdepth\maxdimen +}% + +%---------------------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 +{\escapechar=`\\\relax % makes sure backslash is used in output files. + \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 } + +\newinsert\margin \dimen\margin=\maxdimen + +\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} +{\catcode`\@ =11 +\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +% marginal hacks, juha@viisa.uucp (Juha Takala) +\ifvoid\margin\else % marginal info is present + \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\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 is the rest of +% the input line (except we remove a trailing comment). #1 should be a +% macro which expects an ordinary undelimited TeX argument. +% +\def\parsearg#1{% + \let\next = #1% + \begingroup + \obeylines + \futurelet\temp\parseargx +} + +% If the next token is an obeyed space (from an @example environment or +% the like), remove it and recurse. Otherwise, we're done. +\def\parseargx{% + % \obeyedspace is defined far below, after the definition of \sepspaces. + \ifx\obeyedspace\temp + \expandafter\parseargdiscardspace + \else + \expandafter\parseargline + \fi +} + +% Remove a single space (as the delimiter token to the macro call). +{\obeyspaces % + \gdef\parseargdiscardspace {\futurelet\temp\parseargx}} + +{\obeylines % + \gdef\parseargline#1^^M{% + \endgroup % End of the group started in \parsearg. + % + % First remove any @c comment, then any @comment. + % Result of each macro is put in \toks0. + \argremovec #1\c\relax % + \expandafter\argremovecomment \the\toks0 \comment\relax % + % + % Call the caller's macro, saved as \next in \parsearg. + \expandafter\next\expandafter{\the\toks0}% + }% +} + +% Since all \c{,omment} does is throw away the argument, we can let TeX +% do that for us. The \relax here is matched by the \relax in the call +% in \parseargline; it could be more or less anything, its purpose is +% just to delimit the argument to the \c. +\def\argremovec#1\c#2\relax{\toks0 = {#1}} +\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}} + +% \argremovec{,omment} might leave us with trailing spaces, though; e.g., +% @end itemize @c foo +% will have two active spaces as part of the argument with the +% `itemize'. Here we remove all active spaces from #1, and assign the +% result to \toks0. +% +% This loses if there are any *other* active characters besides spaces +% in the argument -- _ ^ +, for example -- since they get expanded. +% Fortunately, Texinfo does not define any such commands. (If it ever +% does, the catcode of the characters in questionwill have to be changed +% here.) But this means we cannot call \removeactivespaces as part of +% \argremovec{,omment}, since @c uses \parsearg, and thus the argument +% that \parsearg gets might well have any character at all in it. +% +\def\removeactivespaces#1{% + \begingroup + \ignoreactivespaces + \edef\temp{#1}% + \global\toks0 = \expandafter{\temp}% + \endgroup +} + +% Change the active space to expand to nothing. +% +\begingroup + \obeyspaces + \gdef\ignoreactivespaces{\obeyspaces\let =\empty} +\endgroup + + +\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. +% +\def\end{\parsearg\endxxx} +\def\endxxx #1{% + \removeactivespaces{#1}% + \edef\endthing{\the\toks0}% + % + \expandafter\ifx\csname E\endthing\endcsname\relax + \expandafter\ifx\csname \endthing\endcsname\relax + % There's no \foo, i.e., no ``environment'' foo. + \errhelp = \EMsimple + \errmessage{Undefined command `@end \endthing'}% + \else + \unmatchedenderror\endthing + \fi + \else + % Everything's ok; the right environment has been started. + \csname E\endthing\endcsname + \fi +} + +% There is an environment #1, but it hasn't been started. Give an error. +% +\def\unmatchedenderror#1{% + \errhelp = \EMsimple + \errmessage{This `@end #1' doesn't have a matching `@#1'}% +} + +% Define the control sequence \E#1 to give an unmatched @end error. +% +\def\defineunmatchedend#1{% + \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}% +} + + +% Single-spacing is done by various environments (specifically, in +% \nonfillstart and \quotations). +\newskip\singlespaceskip \singlespaceskip = 12.5pt +\def\singlespace{% + % Why was this kern here? It messes up equalizing space above and below + % environments. --karl, 6may93 + %{\advance \baselineskip by -\singlespaceskip + %\kern \baselineskip}% + \setleading \singlespaceskip +} + +%% Simple single-character @ commands + +% @@ prints an @ +% Kludge this until the fonts are right (grr). +\def\@{{\tt \char '100}} + +% This is turned off because it was never documented +% and you can use @w{...} around a quote to suppress ligatures. +%% 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 } + +% @enddots{} is an end-of-sentence ellipsis. +\gdef\enddots{$\mathinner{\ldotp\ldotp\ldotp\ldotp}$\spacefactor=3000} + +% @! is an end-of-sentence bang. +\gdef\!{!\spacefactor=3000 } + +% @? is an end-of-sentence query. +\gdef\?{?\spacefactor=3000 } + +% @w prevents a word break. Without the \leavevmode, @w at the +% beginning of a paragraph, when TeX is still in vertical mode, would +% produce a whole line of output instead of starting the paragraph. +\def\w#1{\leavevmode\hbox{#1}} + +% @group ... @end group forces ... to be all on one page, by enclosing +% it in a TeX vbox. We use \vtop instead of \vbox to construct the box +% to keep its height that of a normal line. According to the rules for +% \topskip (p.114 of the TeXbook), the glue inserted is +% max (\topskip - \ht (first item), 0). If that height is large, +% therefore, no glue is inserted, and the space between the headline and +% the text is small, which looks bad. +% +\def\group{\begingroup + \ifnum\catcode13=\active \else + \errhelp = \groupinvalidhelp + \errmessage{@group invalid in context where filling is enabled}% + \fi + % + % The \vtop we start below produces a box with normal height and large + % depth; thus, TeX puts \baselineskip glue before it, and (when the + % next line of text is done) \lineskip glue after it. (See p.82 of + % the TeXbook.) Thus, space below is not quite equal to space + % above. But it's pretty close. + \def\Egroup{% + \egroup % End the \vtop. + \endgroup % End the \group. + }% + % + \vtop\bgroup + % We have to put a strut on the last line in case the @group is in + % the midst of an example, rather than completely enclosing it. + % Otherwise, the interline space between the last line of the group + % and the first line afterwards is too small. But we can't put the + % strut in \Egroup, since there it would be on a line by itself. + % Hence this just inserts a strut at the beginning of each line. + \everypar = {\strut}% + % + % Since we have a strut on every line, we don't need any of TeX's + % normal interline spacing. + \offinterlineskip + % + % OK, but now we have to do something about blank + % lines in the input in @example-like environments, which normally + % just turn into \lisppar, which will insert no space now that we've + % turned off the interline space. Simplest is to make them be an + % empty paragraph. + \ifx\par\lisppar + \edef\par{\leavevmode \par}% + % + % Reset ^^M's definition to new definition of \par. + \obeylines + \fi + % + % Do @comment since we are called inside an environment such as + % @example, where each end-of-line in the input causes an + % end-of-line in the output. We don't want the end-of-line after + % the `@group' to put extra space in the output. Since @group + % should appear on a line by itself (according to the Texinfo + % manual), we don't worry about eating any user text. + \comment +} +% +% TeX puts in an \escapechar (i.e., `@') at the beginning of the help +% message, so this ends up printing `@group can only ...'. +% +\newhelp\groupinvalidhelp{% +group can only be used in environments such as @example,^^J% +where each line of input produces a line of output.} + +% @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} + +% Old definition--didn't work. +%\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 +%}} + +\def\needx#1{% + % Go into vertical mode, so we don't make a big box in the middle of a + % paragraph. + \par + % + % Don't add any leading before our big empty box, but allow a page + % break, since the best break might be right here. + \allowbreak + \nointerlineskip + \vtop to #1\mil{\vfil}% + % + % TeX does not even consider page breaks if a penalty added to the + % main vertical list is 10000 or more. But in order to see if the + % empty box we just added fits on the page, we must make it consider + % page breaks. On the other hand, we don't want to actually break the + % page after the empty box. So we use a penalty of 9999. + % + % There is an extremely small chance that TeX will actually break the + % page at this \penalty, if there are no other feasible breakpoints in + % sight. (If the user is using lots of big @group commands, which + % almost-but-not-quite fill up a page, TeX will have a hard time doing + % good page breaking, for example.) However, I could not construct an + % example where a page broke at this \penalty; if it happens in a real + % document, then we can reconsider our strategy. + \penalty9999 + % + % Back up by the size of the box, whether we did a page break or not. + \kern -#1\mil + % + % Do not allow a page break right after this kern. + \nobreak +} + +% @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 + +% This records the amount of indent in the innermost environment. +% That's how much \exdent should take out. +\newskip\exdentamount + +% This defn is used inside fill environments such as @defun. +\def\exdent{\parsearg\exdentyyy} +\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}} + +% This defn is used inside nofill environments such as @example. +\def\nofillexdent{\parsearg\nofillexdentyyy} +\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount +\leftline{\hskip\leftskip{\rm#1}}}} + +%\hbox{{\rm#1}}\hfil\break}} + +% @include file insert text of that file as input. + +\def\include{\parsearg\includezzz} +%Use \input\thisfile to avoid blank after \input, which may be an active +%char (in which case the blank would become the \input argument). +%The grouping keeps the value of \thisfile correct even when @include +%is nested. +\def\includezzz #1{\begingroup +\def\thisfile{#1}\input\thisfile +\endgroup} + +\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 +} + +% Used in nested conditionals, where we have to parse the Texinfo source +% and so want to turn off most commands, in case they are used +% incorrectly. +% +\def\ignoremorecommands{% + \let\defcv = \relax + \let\deffn = \relax + \let\deffnx = \relax + \let\defindex = \relax + \let\defivar = \relax + \let\defmac = \relax + \let\defmethod = \relax + \let\defop = \relax + \let\defopt = \relax + \let\defspec = \relax + \let\deftp = \relax + \let\deftypefn = \relax + \let\deftypefun = \relax + \let\deftypevar = \relax + \let\deftypevr = \relax + \let\defun = \relax + \let\defvar = \relax + \let\defvr = \relax + \let\ref = \relax + \let\xref = \relax + \let\printindex = \relax + \let\pxref = \relax + \let\settitle = \relax + \let\include = \relax + \let\lowersections = \relax + \let\down = \relax + \let\raisesections = \relax + \let\up = \relax + \let\set = \relax + \let\clear = \relax + \let\item = \relax + \let\message = \relax +} + +% Ignore @ignore ... @end ignore. +% +\def\ignore{\doignore{ignore}} + +% Also ignore @ifinfo, @ifhtml, @html, @menu, and @direntry text. +% +\def\ifinfo{\doignore{ifinfo}} +\def\ifhtml{\doignore{ifhtml}} +\def\html{\doignore{html}} +\def\menu{\doignore{menu}} +\def\direntry{\doignore{direntry}} + +% Ignore text until a line `@end #1'. +% +\def\doignore#1{\begingroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define a command to swallow text until we reach `@end #1'. + \long\def\doignoretext##1\end #1{\enddoignore}% + % + % Make sure that spaces turn into tokens that match what \doignoretext wants. + \catcode32 = 10 + % + % And now expand that command. + \doignoretext +} + +% What we do to finish off ignored text. +% +\def\enddoignore{\endgroup\ignorespaces}% + +\newif\ifwarnedobs\warnedobsfalse +\def\obstexwarn{% + \ifwarnedobs\relax\else + % We need to warn folks that they may have trouble with TeX 3.0. + % This uses \immediate\write16 rather than \message to get newlines. + \immediate\write16{} + \immediate\write16{***WARNING*** for users of Unix TeX 3.0!} + \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).} + \immediate\write16{If you are running another version of TeX, relax.} + \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.} + \immediate\write16{ Then upgrade your TeX installation if you can.} + \immediate\write16{If you are stuck with version 3.0, run the} + \immediate\write16{ script ``tex3patch'' from the Texinfo distribution} + \immediate\write16{ to use a workaround.} + \immediate\write16{} + \warnedobstrue + \fi +} + +% **In TeX 3.0, setting text in \nullfont hangs tex. For a +% workaround (which requires the file ``dummy.tfm'' to be installed), +% uncomment the following line: +%%%%%\font\nullfont=dummy\let\obstexwarn=\relax + +% Ignore text, except that we keep track of conditional commands for +% purposes of nesting, up to an `@end #1' command. +% +\def\nestedignore#1{% + \obstexwarn + % We must actually expand the ignored text to look for the @end + % command, so that nested ignore constructs work. Thus, we put the + % text into a \vbox and then do nothing with the result. To minimize + % the change of memory overflow, we follow the approach outlined on + % page 401 of the TeXbook: make the current font be a dummy font. + % + \setbox0 = \vbox\bgroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define `@end #1' to end the box, which will in turn undefine the + % @end command again. + \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}% + % + % We are going to be parsing Texinfo commands. Most cause no + % trouble when they are used incorrectly, but some commands do + % complicated argument parsing or otherwise get confused, so we + % undefine them. + % + % We can't do anything about stray @-signs, unfortunately; + % they'll produce `undefined control sequence' errors. + \ignoremorecommands + % + % Set the current font to be \nullfont, a TeX primitive, and define + % all the font commands to also use \nullfont. We don't use + % dummy.tfm, as suggested in the TeXbook, because not all sites + % might have that installed. Therefore, math mode will still + % produce output, but that should be an extremely small amount of + % stuff compared to the main input. + % + \nullfont + \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont + \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont + \let\tensf = \nullfont + % Similarly for index fonts (mostly for their use in + % smallexample) + \let\indrm = \nullfont \let\indit = \nullfont \let\indsl = \nullfont + \let\indbf = \nullfont \let\indtt = \nullfont \let\indsc = \nullfont + \let\indsf = \nullfont + % + % Don't complain when characters are missing from the fonts. + \tracinglostchars = 0 + % + % Don't bother to do space factor calculations. + \frenchspacing + % + % Don't report underfull hboxes. + \hbadness = 10000 + % + % Do minimal line-breaking. + \pretolerance = 10000 + % + % Do not execute instructions in @tex + \def\tex{\doignore{tex}} +} + +% @set VAR sets the variable VAR to an empty value. +% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. +% +% Since we want to separate VAR from REST-OF-LINE (which might be +% empty), we can't just use \parsearg; we have to insert a space of our +% own to delimit the rest of the line, and then take it out again if we +% didn't need it. +% +\def\set{\parsearg\setxxx} +\def\setxxx#1{\setyyy#1 \endsetyyy} +\def\setyyy#1 #2\endsetyyy{% + \def\temp{#2}% + \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty + \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted. + \fi +} +\def\setzzz#1#2 \endsetzzz{\expandafter\xdef\csname SET#1\endcsname{#2}} + +% @clear VAR clears (i.e., unsets) the variable VAR. +% +\def\clear{\parsearg\clearxxx} +\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax} + +% @value{foo} gets the text saved in variable foo. +% +\def\value#1{\expandafter + \ifx\csname SET#1\endcsname\relax + {\{No value for ``#1''\}} + \else \csname SET#1\endcsname \fi} + +% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined +% with @set. +% +\def\ifset{\parsearg\ifsetxxx} +\def\ifsetxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifsetfail + \else + \expandafter\ifsetsucceed + \fi +} +\def\ifsetsucceed{\conditionalsucceed{ifset}} +\def\ifsetfail{\nestedignore{ifset}} +\defineunmatchedend{ifset} + +% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been +% defined with @set, or has been undefined with @clear. +% +\def\ifclear{\parsearg\ifclearxxx} +\def\ifclearxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifclearsucceed + \else + \expandafter\ifclearfail + \fi +} +\def\ifclearsucceed{\conditionalsucceed{ifclear}} +\def\ifclearfail{\nestedignore{ifclear}} +\defineunmatchedend{ifclear} + +% @iftex always succeeds; we read the text following, through @end +% iftex). But `@end iftex' should be valid only after an @iftex. +% +\def\iftex{\conditionalsucceed{iftex}} +\defineunmatchedend{iftex} + +% We can't just want to start a group at @iftex (for example) and end it +% at @end iftex, since then @set commands inside the conditional have no +% effect (they'd get reverted at the end of the group). So we must +% define \Eiftex to redefine itself to be its previous value. (We can't +% just define it to fail again with an ``unmatched end'' error, since +% the @ifset might be nested.) +% +\def\conditionalsucceed#1{% + \edef\temp{% + % Remember the current value of \E#1. + \let\nece{prevE#1} = \nece{E#1}% + % + % At the `@end #1', redefine \E#1 to be its previous value. + \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}% + }% + \temp +} + +% We need to expand lots of \csname's, but we don't want to expand the +% control sequences after we've constructed them. +% +\def\nece#1{\expandafter\noexpand\csname#1\endcsname} + +% @asis just yields its argument. Used with @table, for example. +% +\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} + +% @bullet and @minus need the same treatment as @math, just above. +\def\bullet{\implicitmath\ptexbullet\implicitmath} +\def\minus{\implicitmath-\implicitmath} + +\def\node{\ENVcheck\parsearg\nodezzz} +\def\nodezzz#1{\nodexxx [#1,]} +\def\nodexxx[#1,#2]{\gdef\lastnode{#1}} +\let\nwnode=\node +\let\lastnode=\relax + +\def\donoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\setref{\lastnode}\fi +\global\let\lastnode=\relax} + +\def\unnumbnoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi +\global\let\lastnode=\relax} + +\def\appendixnoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\appendixsetref{\lastnode}\fi +\global\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**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, + node \samp{\ignorespaces#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 + +% Set the font macro #1 to the font named #2, adding on the +% specified font prefix (normally `cm'). +\def\setfont#1#2{\font#1=\fontprefix#2} + +% Use cm as the default font prefix. +% To specify the font prefix, you must define \fontprefix +% before you read in texinfo.tex. +\ifx\fontprefix\undefined +\def\fontprefix{cm} +\fi + +\ifx\bigger\relax +\let\mainmagstep=\magstep1 +\setfont\textrm{r12} +\setfont\texttt{tt12} +\else +\setfont\textrm{r10 scaled \mainmagstep} +\setfont\texttt{tt10 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. +\setfont\textbf{b10 scaled \mainmagstep} +\setfont\textit{ti10 scaled \mainmagstep} +\setfont\textsl{sl10 scaled \mainmagstep} +\setfont\textsf{ss10 scaled \mainmagstep} +\setfont\textsc{csc10 scaled \mainmagstep} +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep + +% A few fonts for @defun, etc. +\setfont\defbf{bx10 scaled \magstep1} %was 1314 +\setfont\deftt{tt10 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. +\setfont\ninett{tt9} +\setfont\indrm{r9} +\setfont\indit{sl9} +\let\indsl=\indit +\let\indtt=\ninett +\let\indsf=\indrm +\let\indbf=\indrm +\let\indsc=\indrm +\font\indi=cmmi9 +\font\indsy=cmsy9 + +% Fonts for headings +\setfont\chaprm{bx12 scaled \magstep2} +\setfont\chapit{ti12 scaled \magstep2} +\setfont\chapsl{sl12 scaled \magstep2} +\setfont\chaptt{tt12 scaled \magstep2} +\setfont\chapsf{ss12 scaled \magstep2} +\let\chapbf=\chaprm +\setfont\chapsc{csc10 scaled\magstep3} +\font\chapi=cmmi12 scaled \magstep2 +\font\chapsy=cmsy10 scaled \magstep3 + +\setfont\secrm{bx12 scaled \magstep1} +\setfont\secit{ti12 scaled \magstep1} +\setfont\secsl{sl12 scaled \magstep1} +\setfont\sectt{tt12 scaled \magstep1} +\setfont\secsf{ss12 scaled \magstep1} +\setfont\secbf{bx12 scaled \magstep1} +\setfont\secsc{csc10 scaled\magstep2} +\font\seci=cmmi12 scaled \magstep1 +\font\secsy=cmsy10 scaled \magstep2 + +% \setfont\ssecrm{bx10 scaled \magstep1} % This size an font looked bad. +% \setfont\ssecit{cmti10 scaled \magstep1} % The letters were too crowded. +% \setfont\ssecsl{sl10 scaled \magstep1} +% \setfont\ssectt{tt10 scaled \magstep1} +% \setfont\ssecsf{ss10 scaled \magstep1} + +%\setfont\ssecrm{b10 scaled 1315} % Note the use of cmb rather than cmbx. +%\setfont\ssecit{ti10 scaled 1315} % Also, the size is a little larger than +%\setfont\ssecsl{sl10 scaled 1315} % being scaled magstep1. +%\setfont\ssectt{tt10 scaled 1315} +%\setfont\ssecsf{ss10 scaled 1315} + +%\let\ssecbf=\ssecrm + +\setfont\ssecrm{bx12 scaled \magstephalf} +\setfont\ssecit{ti12 scaled \magstephalf} +\setfont\ssecsl{sl12 scaled \magstephalf} +\setfont\ssectt{tt12 scaled \magstephalf} +\setfont\ssecsf{ss12 scaled \magstephalf} +\setfont\ssecbf{bx12 scaled \magstephalf} +\setfont\ssecsc{csc10 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: +\setfont\titlerm{bx12 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. +\setfont\shortcontrm{r12} +\setfont\shortcontbf{bx12} +\setfont\shortcontsl{sl12} + +%% 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 + +% We can't just use \exhyphenpenalty, because that only has effect at +% the end of a paragraph. Restore normal hyphenation at the end of the +% group within which \nohyphenation is presumably called. +% +\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} +\def\restorehyphenation{\hyphenchar\font = `- } + +\def\t#1{% + {\tt \nohyphenation \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 \nohyphenation \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. +\def\tclose#1{% + {% + % Change normal interword space to be same as for the current font. + \spaceskip = \fontdimen2\font + % + % Switch to typewriter. + \tt + % + % But `\ ' produces the large typewriter interword space. + \def\ {{\spaceskip = 0pt{} }}% + % + % Turn off hyphenation. + \nohyphenation + % + \rawbackslash + \frenchspacing + #1% + }% + \null +} + +% We *must* turn on hyphenation at `-' and `_' in \code. +% Otherwise, it is too hard to avoid overful hboxes +% in the Emacs manual, the Library manual, etc. + +% Unfortunately, TeX uses one parameter (\hyphenchar) to control +% both hyphenation at - and hyphenation within words. +% We must therefore turn them both off (\tclose does that) +% and arrange explicitly to hyphenate an a dash. +% -- rms. +{ +\catcode`\-=\active +\catcode`\_=\active +\global\def\code{\begingroup \catcode`\-=\active \let-\codedash \catcode`\_=\active \let_\codeunder \codex} +% The following is used by \doprintindex to insure that long function names +% wrap around. It is necessary for - and _ to be active before the index is +% read from the file, as \entry parses the arguments long before \code is +% ever called. -- mycroft +\global\def\indexbreaks{\catcode`\-=\active \let-\realdash \catcode`\_=\active \let_\realunder} +} +\def\realdash{-} +\def\realunder{_} +\def\codedash{-\discretionary{}{}{}} +\def\codeunder{\normalunderscore\discretionary{}{}{}} +\def\codex #1{\tclose{#1}\endgroup} + +%\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}} + +\newif\ifseenauthor +\newif\iffinishedtitlepage + +\def\shorttitlepage{\parsearg\shorttitlepagezzz} +\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page} + +\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 width \hsize \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 width \hsize + \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, @vtable, @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, @vtable, and @vtable define @item, @itemx, etc., with +% these defs. +% They also define \itemindex +% to index the item name in whatever manner is desired (perhaps none). + +\newif\ifitemxneedsnegativevskip + +\def\itemxpar{\par\ifitemxneedsnegativevskip\vskip-\parskip\nobreak\fi} + +\def\internalBitem{\smallbreak \parsearg\itemzzz} +\def\internalBitemx{\itemxpar \parsearg\itemzzz} + +\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz} +\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz} + +\def\internalBkitem{\smallbreak \parsearg\kitemzzz} +\def\internalBkitemx{\itemxpar \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 + % + % Make this a paragraph so we get the \parskip glue and wrapping, + % but leave it ragged-right. + \begingroup + \advance\leftskip by-\tableindent + \advance\hsize by\tableindent + \advance\rightskip by0pt plus1fil + \leavevmode\unhbox0\par + \endgroup + % + % We're going to be starting a paragraph, but we don't want the + % \parskip glue -- logically it's part of the @item we just started. + \nobreak \vskip-\parskip + % + % Stop a page break at the \parskip glue coming up. Unfortunately + % we can't prevent a possible page break at the following + % \baselineskip glue. + \nobreak + \endgroup + \itemxneedsnegativevskipfalse + \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}\ignorespaces% + \endgroup% + \itemxneedsnegativevskiptrue% + \fi +} + +\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\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex} +{\obeylines\obeyspaces% +\gdef\vtablex #1^^M{% +\tabley\vritemindex#1 \endtabley +\def\Evtable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\dontindex #1{} +\def\fnitemindex #1{\doind {fn}{\code{#1}}}% +\def\vritemindex #1{\doind {vr}{\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 % +\exdentamount=\tableindent +\parindent = 0pt +\parskip = \smallskipamount +\ifdim \parskip=0pt \parskip=2pt \fi% +\def\Etable{\endgraf\afterenvbreak\endgroup}% +\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 % +\exdentamount=\itemindent +\parindent = 0pt % +\parskip = \smallskipamount % +\ifdim \parskip=0pt \parskip=2pt \fi% +\def#2{\endgraf\afterenvbreak\endgroup}% +\def\itemcontents{#1}% +\let\item=\itemizeitem} + +% 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} + +% @multitable macros +% Amy Hendrickson, 8/18/94 +% +% @multitable ... @endmultitable will make as many columns as desired. +% Contents of each column will wrap at width given in preamble. Width +% can be specified either with sample text given in a template line, +% or in percent of \hsize, the current width of text on page. + +% Table can continue over pages but will only break between lines. + +% To make preamble: +% +% Either define widths of columns in terms of percent of \hsize: +% @multitable @percentofhsize .2 .3 .5 +% @item ... +% +% Numbers following @percentofhsize are the percent of the total +% current hsize to be used for each column. You may use as many +% columns as desired. + +% Or use a template: +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item ... +% using the widest term desired in each column. + + +% Each new table line starts with @item, each subsequent new column +% starts with @tab. Empty columns may be produced by supplying @tab's +% with nothing between them for as many times as empty columns are needed, +% ie, @tab@tab@tab will produce two empty columns. + +% @item, @tab, @multicolumn or @endmulticolumn do not need to be on their +% own lines, but it will not hurt if they are. + +% Sample multitable: + +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item first col stuff @tab second col stuff @tab third col +% @item +% first col stuff +% @tab +% second col stuff +% @tab +% third col +% @item first col stuff @tab second col stuff +% @tab Many paragraphs of text may be used in any column. +% +% They will wrap at the width determined by the template. +% @item@tab@tab This will be in third column. +% @endmultitable + +% Default dimensions may be reset by user. +% @intableparskip will set vertical space between paragraphs in table. +% @intableparindent will set paragraph indent in table. +% @spacebetweencols will set horizontal space to be left between columns. +% @spacebetweenlines will set vertical space to be left between lines. + +%%%% +% Dimensions + +\newdimen\intableparskip +\newdimen\intableparindent +\newdimen\spacebetweencols +\newdimen\spacebetweenlines +\intableparskip=0pt +\intableparindent=6pt +\spacebetweencols=12pt +\spacebetweenlines=12pt + +%%%% +% Macros used to set up halign preamble: +\let\endsetuptable\relax +\def\xendsetuptable{\endsetuptable} +\let\percentofhsize\relax +\def\xpercentofhsize{\percentofhsize} +\newif\ifsetpercent + +\newcount\colcount +\def\setuptable#1{\def\firstarg{#1}% +\ifx\firstarg\xendsetuptable\let\go\relax% +\else + \ifx\firstarg\xpercentofhsize\global\setpercenttrue% + \else + \ifsetpercent + \if#1.\else% + \global\advance\colcount by1 % + \expandafter\xdef\csname col\the\colcount\endcsname{.#1\hsize}% + \fi + \else + \global\advance\colcount by1 + \setbox0=\hbox{#1}% + \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% + \fi% + \fi% + \let\go\setuptable% +\fi\go} +%%%% +% multitable syntax +\def\tab{&} + +%%%% +% @multitable ... @endmultitable definitions: + +\def\multitable#1\item{\bgroup +\let\item\cr +\tolerance=9500 +\hbadness=9500 +\parskip=\intableparskip +\parindent=\intableparindent +\overfullrule=0pt +\global\colcount=0\relax% +\def\Emultitable{\global\setpercentfalse\global\everycr{}\cr\egroup\egroup}% + % To parse everything between @multitable and @item : +\def\one{#1}\expandafter\setuptable\one\endsetuptable + % Need to reset this to 0 after \setuptable. +\global\colcount=0\relax% + % + % This preamble sets up a generic column definition, which will + % be used as many times as user calls for columns. + % \vtop will set a single line and will also let text wrap and + % continue for many paragraphs if desired. +\halign\bgroup&\global\advance\colcount by 1\relax% +\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname + % In order to keep entries from bumping into each other + % we will add a \leftskip of \spacebetweencols to all columns after + % the first one. + % If a template has been used, we will add \spacebetweencols + % to the width of each template entry. + % If user has set preamble in terms of percent of \hsize + % we will use that dimension as the width of the column, and + % the \leftskip will keep entries from bumping into each other. + % Table will start at left margin and final column will justify at + % right margin. +\ifnum\colcount=1 +\else + \ifsetpercent + \else + % If user has <not> set preamble in terms of percent of \hsize + % we will advance \hsize by \spacebetweencols + \advance\hsize by \spacebetweencols + \fi + % In either case we will make \leftskip=\spacebetweencols: +\leftskip=\spacebetweencols +\fi +\noindent##}\cr% + % \everycr will reset column counter, \colcount, at the end of + % each line. Every column entry will cause \colcount to advance by one. + % The table preamble + % looks at the current \colcount to find the correct column width. +\global\everycr{\noalign{\nointerlineskip\vskip\spacebetweenlines +\filbreak%% keeps underfull box messages off when table breaks over pages. +\global\colcount=0\relax}}} + +\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{% +% Take care of the plain tex accent commands. +\def\"{\realbackslash "}% +\def\`{\realbackslash `}% +\def\'{\realbackslash '}% +\def\^{\realbackslash ^}% +\def\~{\realbackslash ~}% +\def\={\realbackslash =}% +\def\b{\realbackslash b}% +\def\c{\realbackslash c}% +\def\d{\realbackslash d}% +\def\u{\realbackslash u}% +\def\v{\realbackslash v}% +\def\H{\realbackslash H}% +% Take care of the plain tex special European modified letters. +\def\oe{\realbackslash oe}% +\def\ae{\realbackslash ae}% +\def\aa{\realbackslash aa}% +\def\OE{\realbackslash OE}% +\def\AE{\realbackslash AE}% +\def\AA{\realbackslash AA}% +\def\o{\realbackslash o}% +\def\O{\realbackslash O}% +\def\l{\realbackslash l}% +\def\L{\realbackslash L}% +\def\ss{\realbackslash ss}% +% Take care of texinfo commands likely to appear in an index entry. +\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}}% +\def\dfn##1{\realbackslash dfn {##1}}% +\def\emph##1{\realbackslash emph {##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{% +% Just ignore accents. +\let\"=\indexdummyfont +\let\`=\indexdummyfont +\let\'=\indexdummyfont +\let\^=\indexdummyfont +\let\~=\indexdummyfont +\let\==\indexdummyfont +\let\b=\indexdummyfont +\let\c=\indexdummyfont +\let\d=\indexdummyfont +\let\u=\indexdummyfont +\let\v=\indexdummyfont +\let\H=\indexdummyfont +% Take care of the plain tex special European modified letters. +\def\oe{oe}% +\def\ae{ae}% +\def\aa{aa}% +\def\OE{OE}% +\def\AE{AE}% +\def\AA{AA}% +\def\o{o}% +\def\O{O}% +\def\l{l}% +\def\L{L}% +\def\ss{ss}% +\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. + +\let\SETmarginindex=\relax %initialize! +% workhorse for all \fooindexes +% #1 is name of index, #2 is stuff to put there +\def\doind #1#2{% +% Put the index entry in the margin if desired. +\ifx\SETmarginindex\relax\else% +\insert\margin{\hbox{\vrule height8pt depth3pt width0pt #2}}% +\fi% +{\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 + \indexbreaks + % + % 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}} + +% This typesets a paragraph consisting of #1, dot leaders, and then #2 +% flush to the right margin. It is used for index and table of contents +% entries. The paragraph is indented by \leftskip. +% +\def\entry #1#2{\begingroup + % + % Start a new paragraph if necessary, so our assignments below can't + % affect previous text. + \par + % + % Do not fill out the last line with white space. + \parfillskip = 0in + % + % No extra space above this paragraph. + \parskip = 0in + % + % Do not prefer a separate line ending with a hyphen to fewer lines. + \finalhyphendemerits = 0 + % + % \hangindent is only relevant when the entry text and page number + % don't both fit on one line. In that case, bob suggests starting the + % dots pretty far over on the line. Unfortunately, a large + % indentation looks wrong when the entry text itself is broken across + % lines. So we use a small indentation and put up with long leaders. + % + % \hangafter is reset to 1 (which is the value we want) at the start + % of each paragraph, so we need not do anything with that. + \hangindent=2em + % + % When the entry text needs to be broken, just fill out the first line + % with blank space. + \rightskip = 0pt plus1fil + % + % Start a ``paragraph'' for the index entry so the line breaking + % parameters we've set above will have an effect. + \noindent + % + % Insert the text of the index entry. TeX will do line-breaking on it. + #1% + % The following is kluged to not output a line of dots in the index if + % there are no page numbers. The next person who breaks this will be + % cursed by a Unix daemon. + \def\tempa{{\rm }}% + \def\tempb{#2}% + \edef\tempc{\tempa}% + \edef\tempd{\tempb}% + \ifx\tempc\tempd\ \else% + % + % If we must, put the page number on a line of its own, and fill out + % this line with blank space. (The \hfil is overwhelmed with the + % fill leaders glue in \indexdotfill if the page number does fit.) + \hfil\penalty50 + \null\nobreak\indexdotfill % Have leaders before the page number. + % + % The `\ ' here is removed by the implicit \unskip that TeX does as + % part of (the primitive) \par. Without it, a spurious underfull + % \hbox ensues. + \ #2% The page number ends the paragraph. + \fi% + \par +\endgroup} + +% Like \dotfill except takes at least 1 em. +\def\indexdotfill{\cleaders + \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \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 + +\def\begindoublecolumns{\begingroup + % Grab any single-column material above us. + \output = {\global\setbox\partialpage + =\vbox{\unvbox255\kern -\topskip \kern \baselineskip}}% + \eject + % + % Now switch to the double-column output routine. + \output={\doublecolumnout}% + % + % Change the page size parameters. We could do this once outside this + % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 + % format, but then we repeat the same computation. Repeating a couple + % of assignments once per index is clearly meaningless for the + % execution time, so we may as well do it once. + % + % First we halve the line length, less a little for the gutter between + % the columns. We compute the gutter based on the line length, so it + % changes automatically with the paper format. The magic constant + % below is chosen so that the gutter has the same value (well, +- < + % 1pt) as it did when we hard-coded it. + % + % We put the result in a separate register, \doublecolumhsize, so we + % can restore it in \pagesofar, after \hsize itself has (potentially) + % been clobbered. + % + \doublecolumnhsize = \hsize + \advance\doublecolumnhsize by -.04154\hsize + \divide\doublecolumnhsize by 2 + \hsize = \doublecolumnhsize + % + % Double the \vsize as well. (We don't need a separate register here, + % since nobody clobbers \vsize.) + \vsize = 2\vsize + \doublecolumnpagegoal +} + +\def\enddoublecolumns{\eject \endgroup \pagegoal=\vsize \unvbox\partialpage} + +\def\doublecolumnsplit{\splittopskip=\topskip \splitmaxdepth=\maxdepth + \global\dimen@=\pageheight \global\advance\dimen@ by-\ht\partialpage + \global\setbox1=\vsplit255 to\dimen@ \global\setbox0=\vbox{\unvbox1} + \global\setbox3=\vsplit255 to\dimen@ \global\setbox2=\vbox{\unvbox3} + \ifdim\ht0>\dimen@ \setbox255=\vbox{\unvbox0\unvbox2} \global\setbox255=\copy5 \fi + \ifdim\ht2>\dimen@ \setbox255=\vbox{\unvbox0\unvbox2} \global\setbox255=\copy5 \fi +} +\def\doublecolumnpagegoal{% + \dimen@=\vsize \advance\dimen@ by-2\ht\partialpage \global\pagegoal=\dimen@ +} +\def\pagesofar{\unvbox\partialpage % + \hsize=\doublecolumnhsize % have to restore this since output routine + \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}} +\def\doublecolumnout{% + \setbox5=\copy255 + {\vbadness=10000 \doublecolumnsplit} + \ifvbox255 + \setbox0=\vtop to\dimen@{\unvbox0} + \setbox2=\vtop to\dimen@{\unvbox2} + \onepageout\pagesofar \unvbox255 \penalty\outputpenalty + \else + \setbox0=\vbox{\unvbox5} + \ifvbox0 + \dimen@=\ht0 \advance\dimen@ by\topskip \advance\dimen@ by-\baselineskip + \divide\dimen@ by2 \splittopskip=\topskip \splitmaxdepth=\maxdepth + {\vbadness=10000 + \loop \global\setbox5=\copy0 + \setbox1=\vsplit5 to\dimen@ + \setbox3=\vsplit5 to\dimen@ + \ifvbox5 \global\advance\dimen@ by1pt \repeat + \setbox0=\vbox to\dimen@{\unvbox1} + \setbox2=\vbox to\dimen@{\unvbox3} + \global\setbox\partialpage=\vbox{\pagesofar} + \doublecolumnpagegoal + } + \fi + \fi +} + +\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\result{\realbackslash result} +\def\equiv{\realbackslash equiv} +\def\expansion{\realbackslash expansion} +\def\print{\realbackslash print} +\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}} +} + +\newcount\absseclevel % used to calculate proper heading level +\newcount\secbase\secbase=0 % @raise/lowersections modify this count + +% @raisesections: treat @section as chapter, @subsection as section, etc. +\def\raisesections{\global\advance\secbase by -1} +\let\up=\raisesections % original BFox name + +% @lowersections: treat @chapter as section, @section as subsection, etc. +\def\lowersections{\global\advance\secbase by 1} +\let\down=\lowersections % original BFox name + +% Choose a numbered-heading macro +% #1 is heading level if unmodified by @raisesections or @lowersections +% #2 is text for heading +\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \chapterzzz{#2} +\or + \seczzz{#2} +\or + \numberedsubseczzz{#2} +\or + \numberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \chapterzzz{#2} + \else + \numberedsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses appendix heading levels +\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \appendixzzz{#2} +\or + \appendixsectionzzz{#2} +\or + \appendixsubseczzz{#2} +\or + \appendixsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \appendixzzz{#2} + \else + \appendixsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses numberless heading levels +\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \unnumberedzzz{#2} +\or + \unnumberedseczzz{#2} +\or + \unnumberedsubseczzz{#2} +\or + \unnumberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \unnumberedzzz{#2} + \else + \unnumberedsubsubseczzz{#2} + \fi +\fi +} + + +\def\thischaptername{No Chapter Title} +\outer\def\chapter{\parsearg\chapteryyy} +\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz +\def\chapterzzz #1{\seccheck{chapter}% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \chapno by 1 \message{\putwordChapter \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{\putwordChapter{} \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\appendixyyy} +\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz +\def\appendixzzz #1{\seccheck{appendix}% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \appendixno by 1 \message{Appendix \appendixletter}% +\chapmacro {#1}{\putwordAppendix{} \appendixletter}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}% +{\chapternofonts% +\edef\temp{{\realbackslash chapentry + {#1}{\putwordAppendix{} \appendixletter}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\global\let\section = \appendixsec +\global\let\subsection = \appendixsubsec +\global\let\subsubsection = \appendixsubsubsec +}} + +\outer\def\top{\parsearg\unnumberedyyy} +\outer\def\unnumbered{\parsearg\unnumberedyyy} +\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz +\def\unnumberedzzz #1{\seccheck{unnumbered}% +\secno=0 \subsecno=0 \subsubsecno=0 +% +% This used to be simply \message{#1}, but TeX fully expands the +% argument to \message. Therefore, if #1 contained @-commands, TeX +% expanded them. For example, in `@unnumbered The @cite{Book}', TeX +% expanded @cite (which turns out to cause errors because \cite is meant +% to be executed, not expanded). +% +% Anyway, we don't want the fully-expanded definition of @cite to appear +% as a result of the \message, we just want `@cite' itself. We use +% \the<toks register> to achieve this: TeX expands \the<toks> only once, +% simply yielding the contents of the <toks register>. +\toks0 = {#1}\message{(\the\toks0)}% +% +\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\secyyy} +\def\secyyy #1{\numhead1{#1}} % normally calls 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\appenixsection{\parsearg\appendixsecyyy} +\outer\def\appendixsec{\parsearg\appendixsecyyy} +\def\appendixsecyyy #1{\apphead1{#1}} % normally calls 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\unnumberedsecyyy} +\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls 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\numberedsubsecyyy} +\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls 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\appendixsubsecyyy} +\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls 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\unnumberedsubsecyyy} +\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls 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\numberedsubsubsecyyy} +\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally 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\appendixsubsubsecyyy} +\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally 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\unnumberedsubsubsecyyy} +\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally 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{% + \pagealignmacro + \immediate\closeout \contentsfile + \ifnum \pageno>0 + \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 + \catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi + \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{\putwordTableofContents}% + \input \jobname.toc + \endgroup + \vfill \eject +} + +% And just the chapters. +\outer\def\summarycontents{% + \startcontents{\putwordShortContents}% + % + \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{% + \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}% +} + +% Typeset the label for a chapter or appendix for the short contents. +% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter. +% We could simplify the code here by writing out an \appendixentry +% command in the toc file for appendices, instead of using \chapentry +% for both, but it doesn't seem worth it. +\setbox0 = \hbox{\shortcontrm \putwordAppendix } +\newdimen\shortappendixwidth \shortappendixwidth = \wd0 + +\def\shortchaplabel#1{% + % We typeset #1 in a box of constant width, regardless of the text of + % #1, so the chapter titles will come out aligned. + \setbox0 = \hbox{#1}% + \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi + % + % This space should be plenty, since a single number is .5em, and the + % widest letter (M) is 1em, at least in the Computer Modern fonts. + % (This space doesn't include the extra space that gets added after + % the label; that gets put in in \shortchapentry above.) + \advance\dimen0 by 1.1em + \hbox to \dimen0{#1\hfil}% +} + +\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}} +\def\shortunnumberedentry#1#2{\tocentry{#1}{\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 + \begingroup + \chapentryfonts + \tocentry{#1}{\dopageno{#2}}% + \endgroup + \nobreak\vskip .25\baselineskip +} + +\def\dosecentry#1#2{\begingroup + \secentryfonts \leftskip=\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsecentry#1#2{\begingroup + \subsecentryfonts \leftskip=2\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsubsecentry#1#2{\begingroup + \subsubsecentryfonts \leftskip=3\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +% Final typesetting of a toc entry; we use the same \entry macro as for +% the index entries, but we want to suppress hyphenation here. (We +% can't do that in the \entry macro, since index entries might consist +% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.) +% +\def\tocentry#1#2{\begingroup + \hyphenpenalty = 10000 + \entry{#1}{#2}% +\endgroup} + +% 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\hbox to 1em{\hfil$\Rightarrow$\hfil}} +\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} +\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} + +\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} + +% 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\~=\ptextilde +\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, @example, and other +% such environments. \null is better than a space, since it doesn't +% have any width. +\def\lisppar{\null\endgraf} + +% Make each space character in the input produce a normal interword +% space in the output. Don't allow a line break at this space, as this +% is used only in environments like @example, where each line of input +% should produce a line of output anyway. +% +{\obeyspaces % +\gdef\sepspaces{\obeyspaces\let =\tie}} + +% Define \obeyedspace to be our active space, whatever it is. This is +% for use in \parsearg. +{\sepspaces% +\global\let\obeyedspace= } + +% This space is always present above and below environments. +\newskip\envskipamount \envskipamount = 0pt + +% Make spacing and below environment symmetrical. We use \parskip here +% to help in doing that, since in @example-like environments \parskip +% is reset to zero; thus the \afterenvbreak inserts no space -- but the +% start of the next paragraph will insert \parskip +% +\def\aboveenvbreak{{\advance\envskipamount by \parskip +\endgraf \ifdim\lastskip<\envskipamount +\removelastskip \penalty-50 \vskip\envskipamount \fi}} + +\let\afterenvbreak = \aboveenvbreak + +% \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 +}} + + +% This macro is called at the beginning of all the @example variants, +% inside a group. +\def\nonfillstart{% + \aboveenvbreak + \inENV % This group ends at the end of the body + \hfuzz = 12pt % Don't be fussy + \sepspaces % Make spaces be word-separators rather than space tokens. + \singlespace + \let\par = \lisppar % don't ignore blank lines + \obeylines % each line of input is a line of output + \parskip = 0pt + \parindent = 0pt + \emergencystretch = 0pt % don't try to avoid overfull boxes + % @cartouche defines \nonarrowing to inhibit narrowing + % at next level down. + \ifx\nonarrowing\relax + \advance \leftskip by \lispnarrowing + \exdentamount=\lispnarrowing + \let\exdent=\nofillexdent + \let\nonarrowing=\relax + \fi +} + +% To ending an @example-like environment, we first end the paragraph +% (via \afterenvbreak's vertical glue), and then the group. That way we +% keep the zero \parskip that the environments set -- \parskip glue +% will be inserted at the beginning of the next paragraph in the +% document, after the environment. +% +\def\nonfillfinish{\afterenvbreak\endgroup}% + +% This macro is +\def\lisp{\begingroup + \nonfillstart + \let\Elisp = \nonfillfinish + \tt + \rawbackslash % have \ input char produce \ char from current font + \gobble +} + +% Define the \E... control sequence only if we are inside the +% environment, so the error checking in \end will work. +% +% We must call \lisp last in the definition, since it reads the +% return following the @example (or whatever) command. +% +\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp} +\def\smallexample{\begingroup \def\Esmallexample{\nonfillfinish\endgroup}\lisp} +\def\smalllisp{\begingroup \def\Esmalllisp{\nonfillfinish\endgroup}\lisp} + +% @smallexample and @smalllisp. This is not used unless the @smallbook +% command is given. Originally contributed by Pavel@xerox. +% +\def\smalllispx{\begingroup + \nonfillstart + \let\Esmalllisp = \nonfillfinish + \let\Esmallexample = \nonfillfinish + % + % Smaller interline space and fonts for small examples. + \setleading{10pt}% + \indexfonts \tt + \rawbackslash % make \ output the \ character from the current font (tt) + \gobble +} + +% This is @display; same as @lisp except use roman font. +% +\def\display{\begingroup + \nonfillstart + \let\Edisplay = \nonfillfinish + \gobble +} + +% This is @format; same as @display except don't narrow margins. +% +\def\format{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eformat = \nonfillfinish + \gobble +} + +% @flushleft (same as @format) and @flushright. +% +\def\flushleft{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushleft = \nonfillfinish + \gobble +} +\def\flushright{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushright = \nonfillfinish + \advance\leftskip by 0pt plus 1fill + \gobble} + +% @quotation does normal linebreaking (hence we can't use \nonfillstart) +% and narrows the margins. +% +\def\quotation{% + \begingroup\inENV %This group ends at the end of the @quotation body + {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip + \singlespace + \parindent=0pt + % We have retained a nonzero parskip for the environment, since we're + % doing normal filling. So to avoid extra space below the environment... + \def\Equotation{\parskip = 0pt \nonfillfinish}% + % + % @cartouche defines \nonarrowing to inhibit narrowing at next level down. + \ifx\nonarrowing\relax + \advance\leftskip by \lispnarrowing + \advance\rightskip by \lispnarrowing + \exdentamount = \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} + +% Make control sequences which act like normal parenthesis chars. +\let\lparen = ( \let\rparen = ) + +{\activeparens % Now, smart parens don't turn on until &foo (see \amprm) + +% Be sure that we always have a definition for `(', etc. For example, +% if the fn name has parens in it, \boldbrax will not be in effect yet, +% so TeX would otherwise complain about undefined control sequence. +\global\let(=\lparen \global\let)=\rparen +\global\let[=\lbrack \global\let]=\rbrack + +\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 +\exdentamount=\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 +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % 61 is `=' +\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 +\exdentamount=\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 +\exdentamount=\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 +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % +\obeylines\spacesplit#3} + +% This is used for \def{tp,vr}parsebody. It could probably be used for +% some of the others, too, with some judicious conditionals. +% +\def\parsebodycommon#1#2#3{% + \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 + \exdentamount=\defbodyindent + \begingroup\obeylines +} + +\def\defvrparsebody#1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{#3{#4}}% +} + +% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the +% type is just `struct', because we lose the braces in `{struct +% termios}' when \spacesplit reads its undelimited argument. Sigh. +% \let\deftpparsebody=\defvrparsebody +% +% So, to get around this, we put \empty in with the type name. That +% way, TeX won't find exactly `{...}' as an undelimited argument, and +% won't strip off the braces. +% +\def\deftpparsebody #1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{\parsetpheaderline{#3{#4}}}\empty +} + +% Fine, but then we have to eventually remove the \empty *and* the +% braces (if any). That's what this does, putting the result in \tptemp. +% +\def\removeemptybraces\empty#1\relax{\def\tptemp{#1}}% + +% After \spacesplit has done its work, this is called -- #1 is the final +% thing to call, #2 the type name (which starts with \empty), and #3 +% (which might be empty) the arguments. +% +\def\parsetpheaderline#1#2#3{% + \removeemptybraces#2\relax + #1{\tptemp}{#3}% +}% + +\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 +\exdentamount=\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 +\tclose{#1}% avoid \code because of side effects on active chars +\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 {\defheaderxcond#1\relax$$$#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} + +% \defheaderxcond#1\relax$$$ +% puts #1 in @code, followed by a space, but does nothing if #1 is null. +\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi} + +% #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 +\normalparens % notably, turn off `&' magic, which prevents +% at least some C++ text from working +\defname {\defheaderxcond#2\relax$$$#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 {\defheaderxcond#1\relax$$$#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 {\defheaderxcond#2\relax$$$#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{\deftpparsebody\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{\putwordsee{} \xrefX[#1,,,,,,,]} +\def\xref#1{\putwordSee{} \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 + % No printed node name was explicitly given. + \ifx\SETxref-automatic-section-title\relax % + % Use the actual chapter/section title appear inside + % the square brackets. Use the real section title if we have it. + \ifdim \wd1>0pt% + % It is in another manual, so we don't have it. + \def\printednodename{\ignorespaces #1}% + \else + \ifhavexrefs + % We know the real title if we have the xref values. + \def\printednodename{\refx{#1-title}}% + \else + % Otherwise just copy the Info node name. + \def\printednodename{\ignorespaces #1}% + \fi% + \fi + \def\printednodename{#1-title}% + \else + % Use the node name inside the square brackets. + \def\printednodename{\ignorespaces #1}% + \fi + \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 give the text of the node name again, so it + % is as if TeX is seeing it for the first time. + \ifdim \wd1 > 0pt + \putwordsection{} ``\printednodename'' in \cite{\printedmanual}% + \else + % _ (for example) has to be the character _ for the purposes of the + % control sequence corresponding to the node, but it has to expand + % into the usual \leavevmode...\vrule stuff for purposes of + % printing. So we \turnoffactive for the \refx-snt, back on for the + % printing, back off for the \refx-pg. + {\turnoffactive \refx{#1-snt}{}}% + \space [\printednodename],\space + \turnoffactive \putwordpage\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 \auxhat% +\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{\thissection} + +\def\Ynothing{} + +\def\Ysectionnumberandtype{% +\ifnum\secno=0 \putwordChapter\xreftie\the\chapno % +\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\def\Yappendixletterandtype{% +\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}% +\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno % +\else % +\putwordSection\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 +% `\+ does not work, so use 43. +\catcode 43=\other +% Make the characters 128-255 be printing characters +{% + \count 1=128 + \def\loop{% + \catcode\count 1=\other + \advance\count 1 by 1 + \ifnum \count 1<256 \loop \fi + }% +}% +% 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`\^=7 % to make ^^e4 etc usable in xref tags +\catcode `\\=\other +\openin 1 \jobname.aux +\ifeof 1 \else \closein 1 \input \jobname.aux \global\havexrefstrue +\global\warnedobstrue +\fi +% Open the new aux file. Tex will close it automatically at exit. +\openout \auxfile=\jobname.aux +\endgroup} + + +% Footnotes. + +\newcount \footnoteno + +% The trailing space in the following definition for supereject is +% vital for proper filling; pages come out unaligned when you do a +% pagealignmacro call if that space before the closing brace is +% removed. +\def\supereject{\par\penalty -20000\footnoteno =0 } + +% @footnotestyle is meaningful for info output only.. +\let\footnotestyle=\comment + +\let\ptexfootnote=\footnote + +{\catcode `\@=11 +% +% Auto-number footnotes. Otherwise like plain. +\gdef\footnote{% + \global\advance\footnoteno by \@ne + \edef\thisfootno{$^{\the\footnoteno}$}% + % + % In case the footnote comes at the end of a sentence, preserve the + % extra spacing after we do the footnote number. + \let\@sf\empty + \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi + % + % Remove inadvertent blank space before typesetting the footnote number. + \unskip + \thisfootno\@sf + \footnotezzz +}% + +% Don't bother with the trickery in plain.tex to not require the +% footnote text as a parameter. Our footnotes don't need to be so general. +% +\long\gdef\footnotezzz#1{\insert\footins{% + % We want to typeset this text as a normal paragraph, even if the + % footnote reference occurs in (for example) a display environment. + % So reset some parameters. + \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 + \parindent\defaultparindent + % + % Hang the footnote text off the number. + \hang + \textindent{\thisfootno}% + % + % Don't crash into the line above the footnote text. Since this + % expands into a box, it must come within the paragraph, lest it + % provide a place where TeX can split the footnote. + \footstrut + #1\strut}% +} + +}%end \catcode `\@=11 + +% Set the baselineskip to #1, and the lineskip and strut size +% correspondingly. There is no deep meaning behind these magic numbers +% used as factors; they just match (closely enough) what Knuth defined. +% +\def\lineskipfactor{.08333} +\def\strutheightpercent{.70833} +\def\strutdepthpercent {.29167} +% +\def\setleading#1{% + \normalbaselineskip = #1\relax + \normallineskip = \lineskipfactor\normalbaselineskip + \normalbaselines + \setbox\strutbox =\hbox{% + \vrule width0pt height\strutheightpercent\baselineskip + depth \strutdepthpercent \baselineskip + }% +} + +% @| inserts a changebar to the left of the current line. It should +% surround any changed text. This approach does *not* work if the +% change spans more than two lines of output. To handle that, we would +% have adopt a much more difficult approach (putting marks into the main +% vertical list for the beginning and end of each change). +% +\def\|{% + % \vadjust can only be used in horizontal mode. + \leavevmode + % + % Append this vertical mode material after the current line in the output. + \vadjust{% + % We want to insert a rule with the height and depth of the current + % leading; that is exactly what \strutbox is supposed to record. + \vskip-\baselineskip + % + % \vadjust-items are inserted at the left edge of the type. So + % the \llap here moves out into the left-hand margin. + \llap{% + % + % For a thicker or thinner bar, change the `1pt'. + \vrule height\baselineskip width1pt + % + % This is the space between the bar and the text. + \hskip 12pt + }% + }% +} + +% 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} + + +% 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 +\setleading{15pt} +\advance\topskip by 1.2cm + +% Prevent underfull vbox error messages. +\vbadness=10000 + +% Following George Bush, just get rid of widows and orphans. +\widowpenalty=10000 +\clubpenalty=10000 + +% 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 + % Allow us to assign to \emergencystretch anyway. + \def\emergencystretch{\dimen0}% +\else + \emergencystretch = \hsize + \divide\emergencystretch by 45 +\fi + +% Use @smallbook to reset parameters for 7x9.5 format (or else 7x9.25) +\def\smallbook{ + +% These values for secheadingskip and subsecheadingskip are +% experiments. RJC 7 Aug 1992 +\global\secheadingskip = 17pt plus 6pt minus 3pt +\global\subsecheadingskip = 14pt plus 6pt minus 3pt + +\global\lispnarrowing = 0.3in +\setleading{12pt} +\advance\topskip by -1cm +\global\parskip 3pt plus 1pt +\global\hsize = 5in +\global\vsize=7.5in +\global\tolerance=700 +\global\hfuzz=1pt +\global\contentsrightmargin=0pt +\global\deftypemargin=0pt +\global\defbodyindent=.5cm + +\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 +\setleading{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\pagewidth=\hsize +\global\pageheight=\vsize +} + +% Allow control of the text dimensions. Parameters in order: textheight; +% textwidth; \voffset; \hoffset (!); binding offset. All require a dimension; +% header is additional; added length extends the bottom of the page. + +\def\changepagesizes#1#2#3#4#5{ + \global\vsize= #1 + \advance\vsize by \topskip + \global\voffset= #3 + \global\hsize= #2 + \global\outerhsize=\hsize + \global\advance\outerhsize by 0.5in + \global\outervsize=\vsize + \global\advance\outervsize by 0.6in + \global\pagewidth=\hsize + \global\pageheight=\vsize + \global\normaloffset= #4 + \global\bindingoffset= #5} + +% This layout is compatible with Latex on A4 paper. + +\def\afourlatex{\changepagesizes{22cm}{15cm}{7mm}{4.6mm}{5mm}} + +% 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\auxhat{\def^{'hat}} +\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$} + +% 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 + +% Used sometimes to turn off (effectively) the active characters +% even after parsing them. +@def@turnoffactive{@let"=@normaldoublequote +@let\=@realbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +@def@normalturnoffactive{@let"=@normaldoublequote +@let\=@normalbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +% 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.sh b/gnu/usr.bin/cvs/contrib/rcs-to-cvs.sh new file mode 100644 index 00000000000..737beebfc6f --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/rcs-to-cvs.sh @@ -0,0 +1,185 @@ +#! /bin/sh +# +# $Id: rcs-to-cvs.sh,v 1.1.1.1 1995/12/19 09:21:40 deraadt Exp $ +# Based on the CVS 1.0 checkin csh script. +# Contributed by Per Cederqvist <ceder@signum.se>. +# Rewritten in sh by David MacKenzie <djm@cygnus.com>. +# +# Copyright (c) 1989, Brian Berliner +# +# You may distribute under the terms of the GNU General Public License. +# +############################################################################# +# +# Check in sources that previously were under RCS or no source control system. +# +# The repository is the directory where the sources should be deposited. +# +# 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 1.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. +# +# Bugs: doesn't put the files in branch 1.1.1 +# doesn't put in release and vendor tags +# +############################################################################# + +usage="Usage: rcs-to-cvs [-v] [-m message] [-f message_file] repository" +vbose=0 +message="" +message_file=/usr/tmp/checkin.$$ +got_one=0 + +if [ $# -lt 1 ]; then + echo "$usage" >&2 + exit 1 +fi + +while [ $# -ne 0 ]; do + case "$1" in + -v) + vbose=1 + ;; + -m) + shift + echo $1 > $message_file + got_one=1 + ;; + -f) + shift + message_file=$1 + got_one=2 + ;; + *) + break + esac + shift +done + +if [ $# -lt 1 ]; then + echo "$usage" >&2 + exit 1 +fi + +repository=$1 +shift + +if [ -z "$CVSROOT" ]; then + echo "Please the environmental variable CVSROOT to the root" >&2 + echo " of the tree you wish to update" >&2 + exit 1 +fi + +if [ $got_one -eq 0 ]; then + echo "Please Edit this file to contain the RCS log information" >$message_file + echo "to be associated with this directory (please remove these lines)">>$message_file + ${EDITOR-/usr/ucb/vi} $message_file + got_one=1 +fi + +# Ya gotta share. +umask 0 + +update_dir=${CVSROOT}/${repository} +[ ! -d ${update_dir} ] && mkdir $update_dir + +if [ -d SCCS ]; then + echo SCCS files detected! >&2 + exit 1 +fi +if [ -d RCS ]; then + co RCS/* +fi + +for name in * .[a-zA-Z0-9]* +do + case "$name" in + RCS | *~ | \* | .\[a-zA-Z0-9\]\* ) continue ;; + esac + echo $name + if [ $vbose -ne 0 ]; then + echo "Updating ${repository}/${name}" + fi + if [ -d "$name" ]; then + if [ ! -d "${update_dir}/${name}" ]; then + echo "WARNING: Creating new directory ${repository}/${name}" + mkdir "${update_dir}/${name}" + if [ $? -ne 0 ]; then + echo "ERROR: mkdir failed - aborting" >&2 + exit 1 + fi + fi + cd "$name" + if [ $? -ne 0 ]; then + echo "ERROR: Couldn\'t cd to $name - aborting" >&2 + exit 1 + fi + if [ $vbose -ne 0 ]; then + $0 -v -f $message_file "${repository}/${name}" + else + $0 -f $message_file "${repository}/${name}" + fi + if [ $? -ne 0 ]; then + exit 1 + fi + cd .. + else # if not directory + if [ ! -f "$name" ]; then + echo "WARNING: $name is neither a regular file" + echo " nor a directory - ignored" + continue + fi + file="${update_dir}/${name},v" + comment="" + if grep -s '\$Log.*\$' "${name}"; then # If $Log keyword + myext=`echo $name | sed 's,.*\.,,'` + [ "$myext" = "$name" ] && myext= + case "$myext" in + c | csh | e | f | h | l | mac | me | mm | ms | p | r | red | s | sh | sl | cl | ml | el | tex | y | ye | yr | "" ) + ;; + + * ) + echo "For file ${file}:" + grep '\$Log.*\$' "${name}" + echo -n "Please insert a comment leader for file ${name} > " + read comment + ;; + esac + fi + 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 [ -n "${comment}" ]; then + rcs -q -i -c"${comment}" -t${message_file} -m'.' "$file" + fi + ci -q -u1.1 -t${message_file} -m'.' "$file" + if [ $? -ne 0 ]; then + echo "ERROR: Initial check-in of $file failed - aborting" >&2 + exit 1 + fi + fi + else + file="${update_dir}/Attic/${name},v" + echo "WARNING: IGNORED: ${repository}/Attic/${name}" + continue + fi + else # File existed + echo "ERROR: File exists in repository: Ignored: $file" + continue + fi + fi +done + +[ $got_one -eq 1 ] && rm -f $message_file + +exit 0 diff --git a/gnu/usr.bin/cvs/contrib/rcs2log.sh b/gnu/usr.bin/cvs/contrib/rcs2log.sh new file mode 100644 index 00000000000..189905f1e5d --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/rcs2log.sh @@ -0,0 +1,592 @@ +#! /bin/sh + +# RCS to ChangeLog generator + +# Generate a change log prefix from RCS files and the ChangeLog (if any). +# Output the new prefix to standard output. +# You can edit this prefix by hand, and then prepend it to ChangeLog. + +# Ignore log entries that start with `#'. +# Clump together log entries that start with `{topic} ', +# where `topic' contains neither white space nor `}'. + +# Author: Paul Eggert <eggert@twinsun.com> + +# $Id: rcs2log.sh,v 1.1 1995/12/19 09:21:40 deraadt Exp $ + +# Copyright 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + +# 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, 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; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +tab=' ' +nl=' +' + +# Parse options. + +# defaults +: ${AWK=awk} +: ${TMPDIR=/tmp} +hostname= # name of local host (if empty, will deduce it later) +indent=8 # indent of log line +length=79 # suggested max width of log line +logins= # login names for people we know fullnames and mailaddrs of +loginFullnameMailaddrs= # login<tab>fullname<tab>mailaddr triplets +recursive= # t if we want recursive rlog +rlog_options= # options to pass to rlog +tabwidth=8 # width of horizontal tab + +while : +do + case $1 in + -i) indent=${2?}; shift;; + -h) hostname=${2?}; shift;; + -l) length=${2?}; shift;; + -[nu]) # -n is obsolescent; it is replaced by -u. + case $1 in + -n) case ${2?}${3?}${4?} in + *"$tab"* | *"$nl"*) + echo >&2 "$0: -n '$2' '$3' '$4': tabs, newlines not allowed" + exit 1 + esac + loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2$tab$3$tab$4 + shift; shift; shift;; + -u) + # If $2 is not tab-separated, use colon for separator. + case ${2?} in + *"$nl"*) + echo >&2 "$0: -u '$2': newlines not allowed" + exit 1;; + *"$tab"*) + t=$tab;; + *) + t=: + esac + case $2 in + *"$t"*"$t"*"$t"*) + echo >&2 "$0: -u '$2': too many fields" + exit 1;; + *"$t"*"$t"*) + ;; + *) + echo >&2 "$0: -u '$2': not enough fields" + exit 1 + esac + loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2 + shift + esac + logins=$logins$nl$login + ;; + -r) rlog_options=$rlog_options$nl${2?}; shift;; + -R) recursive=t;; + -t) tabwidth=${2?}; shift;; + -*) echo >&2 "$0: usage: $0 [options] [file ...] +Options: + [-h hostname] [-i indent] [-l length] [-R] [-r rlog_option] + [-t tabwidth] [-u 'login<TAB>fullname<TAB>mailaddr']..." + exit 1;; + *) break + esac + shift +done + +month_data=' + m[0]="Jan"; m[1]="Feb"; m[2]="Mar" + m[3]="Apr"; m[4]="May"; m[5]="Jun" + m[6]="Jul"; m[7]="Aug"; m[8]="Sep" + m[9]="Oct"; m[10]="Nov"; m[11]="Dec" + + # days in non-leap year thus far, indexed by month (0-12) + mo[0]=0; mo[1]=31; mo[2]=59; mo[3]=90 + mo[4]=120; mo[5]=151; mo[6]=181; mo[7]=212 + mo[8]=243; mo[9]=273; mo[10]=304; mo[11]=334 + mo[12]=365 +' + + +# Put rlog output into $rlogout. + +# If no rlog options are given, +# log the revisions checked in since the first ChangeLog entry. +case $rlog_options in +'') + date=1970 + if test -s ChangeLog + then + # Add 1 to seconds to avoid duplicating most recent log. + e=' + /^... ... [ 0-9][0-9] [ 0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9]+ /{ + '"$month_data"' + year = $5 + for (i=0; i<=11; i++) if (m[i] == $2) break + dd = $3 + hh = substr($0,12,2) + mm = substr($0,15,2) + ss = substr($0,18,2) + ss++ + if (ss == 60) { + ss = 0 + mm++ + if (mm == 60) { + mm = 0 + hh++ + if (hh == 24) { + hh = 0 + dd++ + monthdays = mo[i+1] - mo[i] + if (i == 1 && year%4 == 0 && (year%100 != 0 || year%400 == 0)) monthdays++ + if (dd == monthdays + 1) { + dd = 1 + i++ + if (i == 12) { + i = 0 + year++ + } + } + } + } + } + # Output comma instead of space to avoid CVS 1.5 bug. + printf "%d/%02d/%02d,%02d:%02d:%02d\n", year,i+1,dd,hh,mm,ss + exit + } + ' + d=`$AWK "$e" <ChangeLog` || exit + case $d in + ?*) date=$d + esac + fi + datearg="-d>$date" +esac + +# If CVS is in use, examine its repository, not the normal RCS files. +if test ! -f CVS/Repository +then + rlog=rlog + repository= +else + rlog='cvs log' + repository=`sed 1q <CVS/Repository` || exit + test ! -f CVS/Root || CVSROOT=`cat <CVS/Root` || exit + case $CVSROOT in + *:/*) + # remote repository + ;; + *) + # local repository + case $repository in + /*) ;; + *) repository=${CVSROOT?}/$repository + esac + if test ! -d "$repository" + then + echo >&2 "$0: $repository: bad repository (see CVS/Repository)" + exit 1 + fi + esac +fi + +# With no arguments, examine all files under the RCS directory. +case $# in +0) + case $repository in + '') + oldIFS=$IFS + IFS=$nl + case $recursive in + t) + RCSdirs=`find . -name RCS -type d -print` + filesFromRCSfiles='s|,v$||; s|/RCS/|/|; s|^\./||' + files=` + { + case $RCSdirs in + ?*) find $RCSdirs -type f -print + esac + find . -name '*,v' -print + } | + sort -u | + sed "$filesFromRCSfiles" + `;; + *) + files= + for file in RCS/.* RCS/* .*,v *,v + do + case $file in + RCS/. | RCS/..) continue;; + RCS/.\* | RCS/\* | .\*,v | \*,v) test -f "$file" || continue + esac + files=$files$nl$file + done + case $files in + '') exit 0 + esac + esac + set x $files + shift + IFS=$oldIFS + esac +esac + +llogout=$TMPDIR/rcs2log$$l +rlogout=$TMPDIR/rcs2log$$r +trap exit 1 2 13 15 +trap "rm -f $llogout $rlogout; exit 1" 0 + +case $rlog_options in +?*) $rlog $rlog_options ${1+"$@"} >$rlogout;; +'') $rlog "$datearg" ${1+"$@"} >$rlogout +esac || exit + + +# Get the full name of each author the logs mention, and set initialize_fullname +# to awk code that initializes the `fullname' awk associative array. +# Warning: foreign authors (i.e. not known in the passwd file) are mishandled; +# you have to fix the resulting output by hand. + +initialize_fullname= +initialize_mailaddr= + +case $loginFullnameMailaddrs in +?*) + case $loginFullnameMailaddrs in + *\"* | *\\*) + sed 's/["\\]/\\&/g' >$llogout <<EOF || exit +$loginFullnameMailaddrs +EOF + loginFullnameMailaddrs=`cat $llogout` + esac + + oldIFS=$IFS + IFS=$nl + for loginFullnameMailaddr in $loginFullnameMailaddrs + do + case $loginFullnameMailaddr in + *"$tab"*) IFS=$tab;; + *) IFS=: + esac + set x $loginFullnameMailaddr + login=$2 + fullname=$3 + mailaddr=$4 + initialize_fullname="$initialize_fullname + fullname[\"$login\"] = \"$fullname\"" + initialize_mailaddr="$initialize_mailaddr + mailaddr[\"$login\"] = \"$mailaddr\"" + done + IFS=$oldIFS +esac + +case $llogout in +?*) sort -u -o $llogout <<EOF || exit +$logins +EOF +esac +output_authors='/^date: / { + if ($2 ~ /^[0-9]*[-\/][0-9][0-9][-\/][0-9][0-9]$/ && $3 ~ /^[0-9][0-9]:[0-9][0-9]:[0-9][0-9][-+0-9:]*;$/ && $4 == "author:" && $5 ~ /^[^;]*;$/) { + print substr($5, 1, length($5)-1) + } +}' +authors=` + $AWK "$output_authors" <$rlogout | + case $llogout in + '') sort -u;; + ?*) sort -u | comm -23 - $llogout + esac +` +case $authors in +?*) + cat >$llogout <<EOF || exit +$authors +EOF + initialize_author_script='s/["\\]/\\&/g; s/.*/author[\"&\"] = 1/' + initialize_author=`sed -e "$initialize_author_script" <$llogout` + awkscript=' + BEGIN { + alphabet = "abcdefghijklmnopqrstuvwxyz" + ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + '"$initialize_author"' + } + { + if (author[$1]) { + fullname = $5 + if (fullname ~ /[0-9]+-[^(]*\([0-9]+\)$/) { + # Remove the junk from fullnames like "0000-Admin(0000)". + fullname = substr(fullname, index(fullname, "-") + 1) + fullname = substr(fullname, 1, index(fullname, "(") - 1) + } + if (fullname ~ /,[^ ]/) { + # Some sites put comma-separated junk after the fullname. + # Remove it, but leave "Bill Gates, Jr" alone. + fullname = substr(fullname, 1, index(fullname, ",") - 1) + } + abbr = index(fullname, "&") + if (abbr) { + a = substr($1, 1, 1) + A = a + i = index(alphabet, a) + if (i) A = substr(ALPHABET, i, 1) + fullname = substr(fullname, 1, abbr-1) A substr($1, 2) substr(fullname, abbr+1) + } + + # Quote quotes and backslashes properly in full names. + # Do not use gsub; traditional awk lacks it. + quoted = "" + rest = fullname + for (;;) { + p = index(rest, "\\") + q = index(rest, "\"") + if (p) { + if (q && q<p) p = q + } else { + if (!q) break + p = q + } + quoted = quoted substr(rest, 1, p-1) "\\" substr(rest, p, 1) + rest = substr(rest, p+1) + } + + printf "fullname[\"%s\"] = \"%s%s\"\n", $1, quoted, rest + author[$1] = 0 + } + } + ' + + initialize_fullname=` + (cat /etc/passwd; ypmatch $authors passwd) 2>/dev/null | + $AWK -F: "$awkscript" + `$initialize_fullname +esac + + +# Function to print a single log line. +# We don't use awk functions, to stay compatible with old awk versions. +# `Log' is the log message (with \n replaced by \r). +# `files' contains the affected files. +printlogline='{ + + # Following the GNU coding standards, rewrite + # * file: (function): comment + # to + # * file (function): comment + if (Log ~ /^\([^)]*\): /) { + i = index(Log, ")") + files = files " " substr(Log, 1, i) + Log = substr(Log, i+3) + } + + # If "label: comment" is too long, break the line after the ":". + sep = " " + if ('"$length"' <= '"$indent"' + 1 + length(files) + index(Log, CR)) sep = "\n" indent_string + + # Print the label. + printf "%s*%s:", indent_string, files + + # Print each line of the log, transliterating \r to \n. + while ((i = index(Log, CR)) != 0) { + logline = substr(Log, 1, i-1) + if (logline ~ /[^'"$tab"' ]/) { + printf "%s%s\n", sep, logline + } else { + print "" + } + sep = indent_string + Log = substr(Log, i+1) + } +}' + +case $hostname in +'') + hostname=`( + hostname || uname -n || uuname -l || cat /etc/whoami + ) 2>/dev/null` || { + echo >&2 "$0: cannot deduce hostname" + exit 1 + } +esac + + +# Process the rlog output, generating ChangeLog style entries. + +# First, reformat the rlog output so that each line contains one log entry. +# Transliterate \n to \r so that multiline entries fit on a single line. +# Discard irrelevant rlog output. +$AWK <$rlogout ' + BEGIN { repository = "'"$repository"'" } + /^RCS file:/ { + if (repository != "") { + filename = $3 + if (substr(filename, 1, length(repository) + 1) == repository "/") { + filename = substr(filename, length(repository) + 2) + } + if (filename ~ /,v$/) { + filename = substr(filename, 1, length(filename) - 2) + } + } + } + /^Working file:/ { if (repository == "") filename = $3 } + /^date: /, /^(-----------*|===========*)$/ { + if ($0 ~ /^branches: /) { next } + if ($0 ~ /^date: [0-9][- +\/0-9:]*;/) { + date = $2 + if (date ~ /-/) { + # An ISO format date. Replace all "-"s with "/"s. + newdate = "" + while ((i = index(date, "-")) != 0) { + newdate = newdate substr(date, 1, i-1) "/" + date = substr(date, i+1) + } + date = newdate date + } + # Ignore any time zone; ChangeLog has no room for it. + time = substr($3, 1, 8) + author = substr($5, 1, length($5)-1) + printf "%s %s %s %s %c", filename, date, time, author, 13 + next + } + if ($0 ~ /^(-----------*|===========*)$/) { print ""; next } + printf "%s%c", $0, 13 + } +' | + +# Now each line is of the form +# FILENAME YYYY/MM/DD HH:MM:SS AUTHOR \rLOG +# where \r stands for a carriage return, +# and each line of the log is terminated by \r instead of \n. +# Sort the log entries, first by date+time (in reverse order), +# then by author, then by log entry, and finally by file name (just in case). +sort +1 -3r +3 +0 | + +# Finally, reformat the sorted log entries. +$AWK ' + BEGIN { + # Some awk variants do not understand "\r" or "\013", so we have to + # put a carriage return directly in the file. + CR="
" # <-- There is a single CR between the " chars here. + + # Initialize the fullname and mailaddr associative arrays. + '"$initialize_fullname"' + '"$initialize_mailaddr"' + + # Initialize indent string. + indent_string = "" + i = '"$indent"' + if (0 < '"$tabwidth"') + for (; '"$tabwidth"' <= i; i -= '"$tabwidth"') + indent_string = indent_string "\t" + while (1 <= i--) + indent_string = indent_string " " + + # Set up date conversion tables. + # RCS uses a nice, clean, sortable format, + # but ChangeLog wants the traditional, ugly ctime format. + + # January 1, 0 AD (Gregorian) was Saturday = 6 + EPOCH_WEEKDAY = 6 + # Of course, there was no 0 AD, but the algorithm works anyway. + + w[0]="Sun"; w[1]="Mon"; w[2]="Tue"; w[3]="Wed" + w[4]="Thu"; w[5]="Fri"; w[6]="Sat" + + '"$month_data"' + } + + { + newlog = substr($0, 1 + index($0, CR)) + + # Ignore log entries prefixed by "#". + if (newlog ~ /^#/) { next } + + if (Log != newlog || date != $2 || author != $4) { + + # The previous log and this log differ. + + # Print the old log. + if (date != "") '"$printlogline"' + + # Logs that begin with "{clumpname} " should be grouped together, + # and the clumpname should be removed. + # Extract the new clumpname from the log header, + # and use it to decide whether to output a blank line. + newclumpname = "" + sep = "\n" + if (date == "") sep = "" + if (newlog ~ /^\{[^'"$tab"' }]*}['"$tab"' ]/) { + i = index(newlog, "}") + newclumpname = substr(newlog, 1, i) + while (substr(newlog, i+1) ~ /^['"$tab"' ]/) i++ + newlog = substr(newlog, i+1) + if (clumpname == newclumpname) sep = "" + } + printf sep + clumpname = newclumpname + + # Get ready for the next log. + Log = newlog + if (files != "") + for (i in filesknown) + filesknown[i] = 0 + files = "" + } + if (date != $2 || author != $4) { + # The previous date+author and this date+author differ. + # Print the new one. + date = $2 + author = $4 + + # Convert nice RCS date like "1992/01/03 00:03:44" + # into ugly ctime date like "Fri Jan 3 00:03:44 1992". + # Calculate day of week from Gregorian calendar. + i = index($2, "/") + year = substr($2, 1, i-1) + 0 + monthday = substr($2, i+1) + i = index(monthday, "/") + month = substr(monthday, 1, i-1) + 0 + day = substr(monthday, i+1) + 0 + leap = 0 + if (2 < month && year%4 == 0 && (year%100 != 0 || year%400 == 0)) leap = 1 + days_since_Sunday_before_epoch = EPOCH_WEEKDAY + year * 365 + int((year + 3) / 4) - int((year + 99) / 100) + int((year + 399) / 400) + mo[month-1] + leap + day - 1 + + # Print "date fullname (email address)". + # Get fullname and email address from associative arrays; + # default to author and author@hostname if not in arrays. + if (fullname[author]) + auth = fullname[author] + else + auth = author + printf "%s %s %2d %s %d %s ", w[days_since_Sunday_before_epoch%7], m[month-1], day, $3, year, auth + if (mailaddr[author]) + printf "<%s>\n\n", mailaddr[author] + else + printf "<%s@%s>\n\n", author, "'"$hostname"'" + } + if (! filesknown[$1]) { + filesknown[$1] = 1 + if (files == "") files = " " $1 + else files = files ", " $1 + } + } + END { + # Print the last log. + if (date != "") { + '"$printlogline"' + printf "\n" + } + } +' && + + +# Exit successfully. + +exec rm -f $llogout $rlogout diff --git a/gnu/usr.bin/cvs/contrib/rcslock.pl b/gnu/usr.bin/cvs/contrib/rcslock.pl new file mode 100644 index 00000000000..01e349ff025 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/rcslock.pl @@ -0,0 +1,235 @@ +#! xPERL_PATHx +# -*-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.csh b/gnu/usr.bin/cvs/contrib/sccs2rcs.csh new file mode 100644 index 00000000000..a9c380be5c6 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/sccs2rcs.csh @@ -0,0 +1,277 @@ +#! xCSH_PATHx -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. +# +# $Id: sccs2rcs.csh,v 1.1 1995/12/19 09:21:40 deraadt 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 |