aboutsummaryrefslogtreecommitdiff
path: root/gnu/usr.bin/cvs/contrib
diff options
context:
space:
mode:
authorcvs2svn <cvs2svn@FreeBSD.org>1996-01-01 11:01:15 +0000
committercvs2svn <cvs2svn@FreeBSD.org>1996-01-01 11:01:15 +0000
commita3ab491d642b34f2d3efbc0562abc8e79b38ce09 (patch)
tree959df5086a97d16c04b83842650d6ee1f3de4522 /gnu/usr.bin/cvs/contrib
parent4e2d078f4fc7fe46c0e3b0f1256c92e971891c67 (diff)
This commit was manufactured by cvs2svn to create tagupstream/2.1.0release/2.1.0
'RELENG_2_1_0_RELEASE'.
Notes
Notes: svn path=/stable/2.1/; revision=13148 svn path=/release/2.1.0/; revision=13149; tag=release/2.1.0
Diffstat (limited to 'gnu/usr.bin/cvs/contrib')
-rw-r--r--gnu/usr.bin/cvs/contrib/clmerge156
-rw-r--r--gnu/usr.bin/cvs/contrib/cvscheck84
-rw-r--r--gnu/usr.bin/cvs/contrib/descend116
-rw-r--r--gnu/usr.bin/cvs/contrib/dirfns481
-rw-r--r--gnu/usr.bin/cvs/contrib/easy-import.perl388
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/cookie.el884
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll-debug.el298
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll.el386
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/elib-node.el89
-rw-r--r--gnu/usr.bin/cvs/contrib/rcs-to-cvs184
-rw-r--r--gnu/usr.bin/cvs/contrib/rcs2log326
-rw-r--r--gnu/usr.bin/cvs/contrib/rcs2sccs143
-rw-r--r--gnu/usr.bin/cvs/contrib/sccs2rcs277
13 files changed, 3812 insertions, 0 deletions
diff --git a/gnu/usr.bin/cvs/contrib/clmerge b/gnu/usr.bin/cvs/contrib/clmerge
new file mode 100644
index 000000000000..1a29311a9c14
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/clmerge
@@ -0,0 +1,156 @@
+#!/usr/local/bin/perl
+
+# Merge conflicted ChangeLogs
+# tromey Mon Aug 15 1994
+
+# Due to popular demand, I'm posting my ChangeLog auto-merge tool. Run
+# this on your ChangeLog files when an update leaves them conflicted.
+# The code is appended.
+#
+# 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.
+#
+# Style comments are welcome. This is my third perl program ever.
+#
+# 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 includie 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
+
+# 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;
+ }
+}
+
+%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);
+
+# 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{$a} <=> $months{$b} 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/cvscheck b/gnu/usr.bin/cvs/contrib/cvscheck
new file mode 100644
index 000000000000..1c66688cbd34
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/cvscheck
@@ -0,0 +1,84 @@
+#! /bin/sh
+# $Id: cvscheck,v 1.2 1992/04/10 03:04:19 berliner Exp $
+#
+# cvscheck - identify files added, changed, or removed
+# in CVS working directory
+#
+# Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
+#
+# This program should be run in a working directory that has been
+# checked out using CVS. It identifies files that have been added,
+# changed, or removed in the working directory, but not "cvs
+# committed". It also determines whether the files have been "cvs
+# added" or "cvs removed". For directories, it is only practical to
+# determine whether they have been added.
+
+name=cvscheck
+changes=0
+
+# If we can't run CVS commands in this directory
+cvs status . > /dev/null 2>&1
+if [ $? != 0 ] ; then
+
+ # Bail out
+ echo "$name: there is no version here; bailing out" 1>&2
+ exit 1
+fi
+
+# Identify files added to working directory
+for file in .* * ; do
+
+ # Skip '.' and '..'
+ if [ $file = '.' -o $file = '..' ] ; then
+ continue
+ fi
+
+ # If a regular file
+ if [ -f $file ] ; then
+ if cvs status $file | grep -s '^From:[ ]*New file' ; then
+ echo "file added: $file - not CVS committed"
+ changes=`expr $changes + 1`
+ elif cvs status $file | grep -s '^From:[ ]*no entry for' ; then
+ echo "file added: $file - not CVS added, not CVS committed"
+ changes=`expr $changes + 1`
+ fi
+
+ # Else if a directory
+ elif [ -d $file -a $file != CVS.adm ] ; then
+
+ # Move into it
+ cd $file
+
+ # If CVS commands don't work inside
+ cvs status . > /dev/null 2>&1
+ if [ $? != 0 ] ; then
+ echo "directory added: $file - not CVS added"
+ changes=`expr $changes + 1`
+ fi
+
+ # Move back up
+ cd ..
+ fi
+done
+
+# Identify changed files
+changedfiles=`cvs diff | egrep '^diff' | awk '{print $3}'`
+for file in $changedfiles ; do
+ echo "file changed: $file - not CVS committed"
+ changes=`expr $changes + 1`
+done
+
+# Identify files removed from working directory
+removedfiles=`cvs status | egrep '^File:[ ]*no file' | awk '{print $4}'`
+
+# Determine whether each file has been cvs removed
+for file in $removedfiles ; do
+ if cvs status $file | grep -s '^From:[ ]*-' ; then
+ echo "file removed: $file - not CVS committed"
+ else
+ echo "file removed: $file - not CVS removed, not CVS committed"
+ fi
+ changes=`expr $changes + 1`
+done
+
+exit $changes
diff --git a/gnu/usr.bin/cvs/contrib/descend b/gnu/usr.bin/cvs/contrib/descend
new file mode 100644
index 000000000000..999c46f4f0a8
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/descend
@@ -0,0 +1,116 @@
+#! /bin/sh
+# $Id: descend,v 1.1 1992/04/03 05:22:52 berliner Exp $
+#
+# descend - walk down a directory tree and execute a command at each node
+
+fullname=$0
+name=descend
+usage="Usage: $name [-afqrv] command [directory ...]\n
+\040\040-a\040\040All: descend into directories starting with '.'\n
+\040\040-f\040\040Force: ignore errors during descent\n
+\040\040-q\040\040Quiet: don't print directory names\n
+\040\040-r\040\040Restricted: don't descend into RCS, CVS.adm, SCCS directories\n
+\040\040-v\040\040Verbose: print command before executing it"
+
+# Scan for options
+while getopts afqrv option; do
+ case $option in
+ a)
+ alldirs=$option
+ options=$options" "-$option
+ ;;
+ f)
+ force=$option
+ options=$options" "-$option
+ ;;
+ q)
+ verbose=
+ quiet=$option
+ options=$options" "-$option
+ ;;
+ r)
+ restricted=$option
+ options=$options" "-$option
+ ;;
+ v)
+ verbose=$option
+ quiet=
+ options=$options" "-$option
+ ;;
+ \?)
+ /usr/5bin/echo $usage 1>&2
+ exit 1
+ ;;
+ esac
+done
+shift `expr $OPTIND - 1`
+
+# Get command to execute
+if [ $# -lt 1 ] ; then
+ /usr/5bin/echo $usage 1>&2
+ exit 1
+else
+ command=$1
+ shift
+fi
+
+# If no directory specified, use '.'
+if [ $# -lt 1 ] ; then
+ default_dir=.
+fi
+
+# For each directory specified
+for dir in $default_dir "$@" ; do
+
+ # Spawn sub-shell so we return to starting directory afterward
+ (cd $dir
+
+ # Execute specified command
+ if [ -z "$quiet" ] ; then
+ echo In directory `hostname`:`pwd`
+ fi
+ if [ -n "$verbose" ] ; then
+ echo $command
+ fi
+ eval "$command" || if [ -z "$force" ] ; then exit 1; fi
+
+ # Collect dot file names if necessary
+ if [ -n "$alldirs" ] ; then
+ dotfiles=.*
+ else
+ dotfiles=
+ fi
+
+ # For each file in current directory
+ for file in $dotfiles * ; do
+
+ # Skip '.' and '..'
+ if [ "$file" = "." -o "$file" = ".." ] ; then
+ continue
+ fi
+
+ # If a directory but not a symbolic link
+ if [ -d "$file" -a ! -h "$file" ] ; then
+
+ # If not skipping this type of directory
+ if [ \( "$file" != "RCS" -a \
+ "$file" != "SCCS" -a \
+ "$file" != "CVS" -a \
+ "$file" != "CVS.adm" \) \
+ -o -z "$restricted" ] ; then
+
+ # Recursively descend into it
+ $fullname $options "$command" "$file" \
+ || if [ -z "$force" ] ; then exit 1; fi
+ fi
+
+ # Else if a directory AND a symbolic link
+ elif [ -d "$file" -a -h "$file" ] ; then
+
+ if [ -z "$quiet" ] ; then
+ echo In directory `hostname`:`pwd`/$file: symbolic link: skipping
+ fi
+ fi
+ done
+ ) || if [ -z "$force" ] ; then exit 1; fi
+done
diff --git a/gnu/usr.bin/cvs/contrib/dirfns b/gnu/usr.bin/cvs/contrib/dirfns
new file mode 100644
index 000000000000..8324c4198e35
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/dirfns
@@ -0,0 +1,481 @@
+echo 'directory.3':
+sed 's/^X//' >'directory.3' <<'!'
+X.TH DIRECTORY 3 imported
+X.DA 9 Oct 1985
+X.SH NAME
+Xopendir, readdir, telldir, seekdir, rewinddir, closedir \- high-level directory operations
+X.SH SYNOPSIS
+X.B #include <sys/types.h>
+X.br
+X.B #include <ndir.h>
+X.PP
+X.SM
+X.B DIR
+X.B *opendir(filename)
+X.br
+X.B char *filename;
+X.PP
+X.SM
+X.B struct direct
+X.B *readdir(dirp)
+X.br
+X.B DIR *dirp;
+X.PP
+X.SM
+X.B long
+X.B telldir(dirp)
+X.br
+X.B DIR *dirp;
+X.PP
+X.SM
+X.B seekdir(dirp, loc)
+X.br
+X.B DIR *dirp;
+X.br
+X.B long loc;
+X.PP
+X.SM
+X.B rewinddir(dirp)
+X.br
+X.B DIR *dirp;
+X.PP
+X.SM
+X.B closedir(dirp)
+X.br
+X.B DIR *dirp;
+X.SH DESCRIPTION
+XThis library provides high-level primitives for directory scanning,
+Xsimilar to those available for 4.2BSD's (very different) directory system.
+X.\"The purpose of this library is to simulate
+X.\"the new flexible length directory names of 4.2bsd UNIX
+X.\"on top of the old directory structure of v7.
+XIt incidentally provides easy portability to and from 4.2BSD (insofar
+Xas such portability is not compromised by other 4.2/VAX dependencies).
+X.\"It allows programs to be converted immediately
+X.\"to the new directory access interface,
+X.\"so that they need only be relinked
+X.\"when moved to 4.2bsd.
+X.\"It is obtained with the loader option
+X.\".BR \-lndir .
+X.PP
+X.I Opendir
+Xopens the directory named by
+X.I filename
+Xand associates a
+X.I directory stream
+Xwith it.
+X.I Opendir
+Xreturns a pointer to be used to identify the
+X.I directory stream
+Xin subsequent operations.
+XThe pointer
+X.SM
+X.B NULL
+Xis returned if
+X.I filename
+Xcannot be accessed or is not a directory.
+X.PP
+X.I Readdir
+Xreturns a pointer to the next directory entry.
+XIt returns
+X.B NULL
+Xupon reaching the end of the directory or detecting
+Xan invalid
+X.I seekdir
+Xoperation.
+X.PP
+X.I Telldir
+Xreturns the current location associated with the named
+X.I directory stream.
+X.PP
+X.I Seekdir
+Xsets the position of the next
+X.I readdir
+Xoperation on the
+X.I directory stream.
+XThe new position reverts to the one associated with the
+X.I directory stream
+Xwhen the
+X.I telldir
+Xoperation was performed.
+XValues returned by
+X.I telldir
+Xare good only for the lifetime of the DIR pointer from
+Xwhich they are derived.
+XIf the directory is closed and then reopened,
+Xthe
+X.I telldir
+Xvalue may be invalidated
+Xdue to undetected directory compaction in 4.2BSD.
+XIt is safe to use a previous
+X.I telldir
+Xvalue immediately after a call to
+X.I opendir
+Xand before any calls to
+X.I readdir.
+X.PP
+X.I Rewinddir
+Xresets the position of the named
+X.I directory stream
+Xto the beginning of the directory.
+X.PP
+X.I Closedir
+Xcauses the named
+X.I directory stream
+Xto be closed,
+Xand the structure associated with the DIR pointer to be freed.
+X.PP
+XA
+X.I direct
+Xstructure is as follows:
+X.PP
+X.RS
+X.nf
+Xstruct direct {
+X /* unsigned */ long d_ino; /* inode number of entry */
+X unsigned short d_reclen; /* length of this record */
+X unsigned short d_namlen; /* length of string in d_name */
+X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+X};
+X.fi
+X.RE
+X.PP
+XThe
+X.I d_reclen
+Xfield is meaningless in non-4.2BSD systems and should be ignored.
+XThe use of a
+X.I long
+Xfor
+X.I d_ino
+Xis also a 4.2BSDism;
+X.I ino_t
+X(see
+X.IR types (5))
+Xshould be used elsewhere.
+XThe macro
+X.I DIRSIZ(dp)
+Xgives the minimum memory size needed to hold the
+X.I direct
+Xvalue pointed to by
+X.IR dp ,
+Xwith the minimum necessary allocation for
+X.IR d_name .
+X.PP
+XThe preferred way to search the current directory for entry ``name'' is:
+X.PP
+X.RS
+X.nf
+X len = strlen(name);
+X dirp = opendir(".");
+X if (dirp == NULL) {
+X fprintf(stderr, "%s: can't read directory .\\n", argv[0]);
+X return NOT_FOUND;
+X }
+X while ((dp = readdir(dirp)) != NULL)
+X if (dp->d_namlen == len && strcmp(dp->d_name, name) == 0) {
+X closedir(dirp);
+X return FOUND;
+X }
+X closedir(dirp);
+X return NOT_FOUND;
+X.RE
+X.\".SH LINKING
+X.\"This library is accessed by specifying ``-lndir'' as the
+X.\"last argument to the compile line, e.g.:
+X.\".PP
+X.\" cc -I/usr/include/ndir -o prog prog.c -lndir
+X.SH "SEE ALSO"
+Xopen(2),
+Xclose(2),
+Xread(2),
+Xlseek(2)
+X.SH HISTORY
+XWritten by
+XKirk McKusick at Berkeley (ucbvax!mckusick).
+XMiscellaneous bug fixes from elsewhere.
+XThe size of the data structure has been decreased to avoid excessive
+Xspace waste under V7 (where filenames are 14 characters at most).
+XFor obscure historical reasons, the include file is also available
+Xas
+X.IR <ndir/sys/dir.h> .
+XThe Berkeley version lived in a separate library (\fI\-lndir\fR),
+Xwhereas ours is
+Xpart of the C library, although the separate library is retained to
+Xmaximize compatibility.
+X.PP
+XThis manual page has been substantially rewritten to be informative in
+Xthe absence of a 4.2BSD manual.
+X.SH BUGS
+XThe
+X.I DIRSIZ
+Xmacro actually wastes a bit of space due to some padding requirements
+Xthat are an artifact of 4.2BSD.
+X.PP
+XThe returned value of
+X.I readdir
+Xpoints to a static area that will be overwritten by subsequent calls.
+X.PP
+XThere are some unfortunate name conflicts with the \fIreal\fR V7
+Xdirectory structure definitions.
+!
+echo 'dir.h':
+sed 's/^X//' >'dir.h' <<'!'
+X/* dir.h 4.4 82/07/25 */
+X
+X/*
+X * A directory consists of some number of blocks of DIRBLKSIZ
+X * bytes, where DIRBLKSIZ is chosen such that it can be transferred
+X * to disk in a single atomic operation (e.g. 512 bytes on most machines).
+X *
+X * Each DIRBLKSIZ byte block contains some number of directory entry
+X * structures, which are of variable length. Each directory entry has
+X * a struct direct at the front of it, containing its inode number,
+X * the length of the entry, and the length of the name contained in
+X * the entry. These are followed by the name padded to a 4 byte boundary
+X * with null bytes. All names are guaranteed null terminated.
+X * The maximum length of a name in a directory is MAXNAMLEN.
+X *
+X * The macro DIRSIZ(dp) gives the amount of space required to represent
+X * a directory entry. Free space in a directory is represented by
+X * entries which have dp->d_reclen >= DIRSIZ(dp). All DIRBLKSIZ bytes
+X * in a directory block are claimed by the directory entries. This
+X * usually results in the last entry in a directory having a large
+X * dp->d_reclen. When entries are deleted from a directory, the
+X * space is returned to the previous entry in the same directory
+X * block by increasing its dp->d_reclen. If the first entry of
+X * a directory block is free, then its dp->d_ino is set to 0.
+X * Entries other than the first in a directory do not normally have
+X * dp->d_ino set to 0.
+X */
+X#define DIRBLKSIZ 512
+X#ifdef VMUNIX
+X#define MAXNAMLEN 255
+X#else
+X#define MAXNAMLEN 14
+X#endif
+X
+Xstruct direct {
+X /* unsigned */ long d_ino; /* inode number of entry */
+X unsigned short d_reclen; /* length of this record */
+X unsigned short d_namlen; /* length of string in d_name */
+X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+X};
+X
+X/*
+X * The DIRSIZ macro gives the minimum record length which will hold
+X * the directory entry. This requires the amount of space in struct direct
+X * without the d_name field, plus enough space for the name with a terminating
+X * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
+X */
+X#undef DIRSIZ
+X#define DIRSIZ(dp) \
+X ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
+X
+X#ifndef KERNEL
+X/*
+X * Definitions for library routines operating on directories.
+X */
+Xtypedef struct _dirdesc {
+X int dd_fd;
+X long dd_loc;
+X long dd_size;
+X char dd_buf[DIRBLKSIZ];
+X} DIR;
+X#ifndef NULL
+X#define NULL 0
+X#endif
+Xextern DIR *opendir();
+Xextern struct direct *readdir();
+Xextern long telldir();
+X#ifdef void
+Xextern void seekdir();
+Xextern void closedir();
+X#endif
+X#define rewinddir(dirp) seekdir((dirp), (long)0)
+X#endif KERNEL
+!
+echo 'makefile':
+sed 's/^X//' >'makefile' <<'!'
+XDIR = closedir.o opendir.o readdir.o seekdir.o telldir.o
+XCFLAGS=-O -I. -Dvoid=int
+XDEST=..
+X
+Xall: $(DIR)
+X
+Xmv: $(DIR)
+X mv $(DIR) $(DEST)
+X
+Xcpif: dir.h
+X cp dir.h /usr/include/ndir.h
+X
+Xclean:
+X rm -f *.o
+!
+echo 'closedir.c':
+sed 's/^X//' >'closedir.c' <<'!'
+Xstatic char sccsid[] = "@(#)closedir.c 4.2 3/10/82";
+X
+X#include <sys/types.h>
+X#include <dir.h>
+X
+X/*
+X * close a directory.
+X */
+Xvoid
+Xclosedir(dirp)
+X register DIR *dirp;
+X{
+X close(dirp->dd_fd);
+X dirp->dd_fd = -1;
+X dirp->dd_loc = 0;
+X free((char *)dirp);
+X}
+!
+echo 'opendir.c':
+sed 's/^X//' >'opendir.c' <<'!'
+X/* Copyright (c) 1982 Regents of the University of California */
+X
+Xstatic char sccsid[] = "@(#)opendir.c 4.4 11/12/82";
+X
+X#include <sys/types.h>
+X#include <sys/stat.h>
+X#include <dir.h>
+X
+X/*
+X * open a directory.
+X */
+XDIR *
+Xopendir(name)
+X char *name;
+X{
+X register DIR *dirp;
+X register int fd;
+X struct stat statbuf;
+X char *malloc();
+X
+X if ((fd = open(name, 0)) == -1)
+X return NULL;
+X if (fstat(fd, &statbuf) == -1 || !(statbuf.st_mode & S_IFDIR)) {
+X close(fd);
+X return NULL;
+X }
+X if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
+X close (fd);
+X return NULL;
+X }
+X dirp->dd_fd = fd;
+X dirp->dd_loc = 0;
+X dirp->dd_size = 0; /* so that telldir will work before readdir */
+X return dirp;
+X}
+!
+echo 'readdir.c':
+sed 's/^X//' >'readdir.c' <<'!'
+X/* Copyright (c) 1982 Regents of the University of California */
+X
+Xstatic char sccsid[] = "@(#)readdir.c 4.3 8/8/82";
+X
+X#include <sys/types.h>
+X#include <dir.h>
+X
+X/*
+X * read an old stlye directory entry and present it as a new one
+X */
+X#define ODIRSIZ 14
+X
+Xstruct olddirect {
+X ino_t od_ino;
+X char od_name[ODIRSIZ];
+X};
+X
+X/*
+X * get next entry in a directory.
+X */
+Xstruct direct *
+Xreaddir(dirp)
+X register DIR *dirp;
+X{
+X register struct olddirect *dp;
+X static struct direct dir;
+X
+X for (;;) {
+X if (dirp->dd_loc == 0) {
+X dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
+X DIRBLKSIZ);
+X if (dirp->dd_size <= 0) {
+X dirp->dd_size = 0;
+X return NULL;
+X }
+X }
+X if (dirp->dd_loc >= dirp->dd_size) {
+X dirp->dd_loc = 0;
+X continue;
+X }
+X dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc);
+X dirp->dd_loc += sizeof(struct olddirect);
+X if (dp->od_ino == 0)
+X continue;
+X dir.d_ino = dp->od_ino;
+X strncpy(dir.d_name, dp->od_name, ODIRSIZ);
+X dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */
+X dir.d_namlen = strlen(dir.d_name);
+X dir.d_reclen = DIRBLKSIZ;
+X return (&dir);
+X }
+X}
+!
+echo 'seekdir.c':
+sed 's/^X//' >'seekdir.c' <<'!'
+Xstatic char sccsid[] = "@(#)seekdir.c 4.9 3/25/83";
+X
+X#include <sys/param.h>
+X#include <dir.h>
+X
+X/*
+X * seek to an entry in a directory.
+X * Only values returned by "telldir" should be passed to seekdir.
+X */
+Xvoid
+Xseekdir(dirp, loc)
+X register DIR *dirp;
+X long loc;
+X{
+X long curloc, base, offset;
+X struct direct *dp;
+X extern long lseek();
+X
+X curloc = telldir(dirp);
+X if (loc == curloc)
+X return;
+X base = loc & ~(DIRBLKSIZ - 1);
+X offset = loc & (DIRBLKSIZ - 1);
+X (void) lseek(dirp->dd_fd, base, 0);
+X dirp->dd_size = 0;
+X dirp->dd_loc = 0;
+X while (dirp->dd_loc < offset) {
+X dp = readdir(dirp);
+X if (dp == NULL)
+X return;
+X }
+X}
+!
+echo 'telldir.c':
+sed 's/^X//' >'telldir.c' <<'!'
+Xstatic char sccsid[] = "@(#)telldir.c 4.1 2/21/82";
+X
+X#include <sys/types.h>
+X#include <dir.h>
+X
+X/*
+X * return a pointer into a directory
+X */
+Xlong
+Xtelldir(dirp)
+X DIR *dirp;
+X{
+X long lseek();
+X
+X return (lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc);
+X}
+!
+echo done
diff --git a/gnu/usr.bin/cvs/contrib/easy-import.perl b/gnu/usr.bin/cvs/contrib/easy-import.perl
new file mode 100644
index 000000000000..44f6f4cb2938
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/easy-import.perl
@@ -0,0 +1,388 @@
+#!/usr/bin/perl
+#
+# Support for importing a source collection into CVS.
+# Tries to prevent the user from the most common pitfalls (like creating
+# new top-level repositories or second-level areas accidentally), and
+# cares to do some of the `dirty' work like maintaining the modules
+# database accordingly.
+#
+# Written by Jörg Wunsch, 95/03/07, and placed in the public domain.
+#
+# $Id: easy-import.perl,v 1.3 1995/07/23 17:34:00 joerg Exp $
+
+require "complete.pl";
+require "getopts.pl";
+
+
+sub scan_opts
+{
+ local($status);
+
+ $status = &Getopts("nv");
+
+ $dont_do_it = "-n" if $opt_n;
+ if($opt_v) {
+ print STDERR '$Source: /home/ncvs/src/gnu/usr.bin/cvs/contrib/easy-import.perl,v $ $Revision: 1.3 $' . "\n"; # 'emacs kludge
+ exit 0;
+ }
+ die "usage: $0 [-v] [-n] [moduledir]\n" .
+ " -n: don't do any commit, show only\n" .
+ " -v: show program version\n"
+ unless $status && $#ARGV <= 0;
+
+ if($#ARGV == 0) {
+ $moduledir = $ARGV[0];
+ shift;
+ }
+}
+
+sub lsdir
+{
+ # find all subdirectories under @_
+ # ignore all CVS entries, dot entries, and non-directories
+
+ local($base) = @_;
+ local(@ls, @rv, $fname);
+
+ opendir(DIR, $base) || die "Cannot find dir $base.\n";
+
+ @ls = readdir(DIR);
+ closedir(DIR);
+
+ @rv = ();
+
+ foreach $fname (@ls) {
+ next if $fname =~ /^CVS/ || $fname eq "Attic"
+ || $fname =~ /^\./ || ! -d "$base/$fname";
+ @rv = (@rv, $fname);
+ }
+
+ return sort(@rv);
+}
+
+
+sub contains
+{
+ # look if the first parameter is contained in the list following it
+ local($item, @list) = @_;
+ local($found, $i);
+
+ $found = 0;
+ foreach $i (@list) {
+ return 1 if $i eq $item;
+ }
+ return 0;
+}
+
+
+
+sub term_init
+{
+ # first, get some terminal attributes
+
+ # try bold mode first
+ $so = `tput md`; $se = `tput me`;
+
+ # if no bold mode available, use standout mode
+ if ($so eq "") {
+ $so = `tput so`; $se = `tput se`;
+ }
+
+ # try if we can underscore
+ $us = `tput us`; $ue = `tput ue`;
+ # if we don't have it available, or same as bold/standout, disable it
+ if ($us eq "" || $us eq $so) {
+ $us = $ue = "";
+ }
+
+ # look how many columns we've got
+ if($ENV{'COLUMNS'} ne "") {
+ $columns = $ENV{'COLUMNS'};
+ } elsif(-t STDIN) { # if we operate on a terminal...
+ local($word, $tmp);
+
+ open(STTY, "stty -a|");
+ $_ = <STTY>; # try getting the tty win structure value
+ close(STTY);
+ chop;
+ $columns = 0;
+ foreach $word (split) {
+ $columns = $tmp if $word eq "columns;"; # the number preceding
+ $tmp = $word;
+ }
+ } else {
+ $columns = 80;
+ }
+ # sanity
+ $columns = 80 unless $columns >= 5;
+}
+
+
+sub list
+{
+ # pretty-print a list
+ # imports: global variable $columns
+ local(@items) = @_;
+ local($longest,$i,$item,$cols,$width);
+
+ # find the longest item
+ $longest = 0;
+ foreach $item (@items) {
+ $i = length($item);
+ $longest = $i if $longest < $i;
+ }
+ $width = $longest + 1;
+ $cols = int($columns / $width);
+
+ $i = 0;
+ foreach $item (@items) {
+ print $item;
+ if(++$i == $cols) {
+ $i = 0; print "\n";
+ } else {
+ print ' ' x ($width - length($item));
+ }
+ }
+ print "\n" unless $i == 0;
+}
+
+sub cvs_init
+{
+ # get the CVS repository(s)
+
+ die "You need to have the \$CVSROOT variable set.\n"
+ unless $ENV{'CVSROOT'} ne "";
+
+ # get the list of available repositories
+ $cvsroot = $ENV{'CVSROOT'};
+ @reps = &lsdir($cvsroot);
+}
+
+
+sub lsmodules
+{
+ # list all known CVS modules
+ local(@rv, $mname, $_);
+
+ @rv = ();
+
+ open(CVS, "cvs co -c|");
+ while($_ = <CVS>) {
+ chop;
+ ($mname) = split;
+ next if $mname eq "";
+ @rv = (@rv, $mname);
+ }
+ close(CVS);
+
+ return @rv;
+}
+
+
+sub checktag
+{
+ # check a given string for tag rules
+ local($s, $name) = @_;
+ local($regexp);
+
+ if($name eq "vendor") { $regexp = '^[A-Z][A-Z0-9_]*$'; }
+ elsif($name eq "release") { $regexp = '^[a-z][a-z0-9_]*$'; }
+ else {
+ print STDERR "Internal error: unknown tag name $name\n";
+ exit(2);
+ }
+
+ if($s !~ /$regexp/) {
+ print "\a${us}Valid $name tags must match the regexp " .
+ "$regexp.${ue}\n";
+ return 0;
+ }
+ if($s =~ /^RELENG/) {
+ print "\a${us}Tags must not start with the word \"RELENG\".${ue}\n";
+ return 0;
+ }
+
+ return 1;
+}
+
+
+&scan_opts;
+&term_init;
+&cvs_init;
+
+if(! $moduledir) {
+ @dirs = &lsdir(".");
+ print "${so}Import from which directory?${se}\n";
+ @dirs = (@dirs, ".");
+ &list(@dirs);
+ $moduledir = &Complete("Which? [.]: ", @dirs);
+ $moduledir = "." unless $moduledir ne "";
+}
+
+chdir $moduledir || die "Cannot chdir to $moduledir\n";
+
+print "${so}Available repositories:${se}\n";
+&list(@reps);
+
+# the following kludge prevents the Complete package from starting
+# over with the string just selected; Complete should better provide
+# some reinitialize method
+$Complete'return = ""; $Complete'r = 0;
+
+$selected =
+ &Complete("Enter repository (<TAB>=complete, ^D=show): ",
+ @reps);
+
+die "\aYou cannot create new repositories with this script.\n"
+ unless &contains($selected, @reps);
+
+$rep = $selected;
+
+print "\n${so}Selected repository:${se} ${us}$rep${ue}\n";
+
+
+@areas = &lsdir("$cvsroot/$rep");
+
+print "${so}Existent areas in this repository:${se}\n";
+&list(@areas);
+
+$Complete'return = ""; $Complete'r = 0;
+
+$selected =
+ &Complete("Enter area name (<TAB>=complete, ^D=show): ",
+ @areas);
+
+print "\a${us}Warning: this will create a new area.${ue}\n"
+ unless &contains($selected, @areas);
+
+$area = "$rep/$selected";
+
+print "\n${so}[Working on:${se} ${us}$area${ue}${so}]${se}\n";
+
+for(;;) {
+ $| = 1;
+ print "${so}Enter the module path:${se} $area/";
+ $| = 0;
+ $modpath = <>;
+ chop $modpath;
+ if ($modpath eq "") {
+ print "\a${us}You cannot use an empty module path.${ue}\n";
+ next;
+ }
+ last if ! -d "$cvsroot/$area/$modpath";
+ print "\a${us}This module path does already exist; " .
+ "choose another one.${ue}\n";
+}
+
+
+@newdirs = ();
+$dir1 = "$cvsroot/$area";
+$dir2 = "$area";
+
+@newdirs = (@newdirs, "$dir2") if ! -d $dir1;
+
+foreach $ele (split(/\//, $modpath)) {
+ $dir1 = "$dir1/$ele";
+ $dir2 = "$dir2/$ele";
+ @newdirs = (@newdirs, "$dir2") if ! -d $dir1;
+}
+
+print "${so}You're going to create the following new directories:${se}\n";
+
+&list(@newdirs);
+
+@cvsmods = &lsmodules();
+
+for(;;) {
+ $| = 1;
+ print "${so}Gimme the module name:${se} ";
+ $| = 0;
+ $modname = <>;
+ chop $modname;
+ if ($modname eq "") {
+ print "\a${us}You cannot use an empty module name.${ue}\n";
+ next;
+ }
+ last if !&contains($modname, @cvsmods);
+ print "\a${us}This module name does already exist; " .
+ "choose another one.${ue}\n";
+}
+
+
+for(;;) {
+ $| = 1;
+ print "${so}Enter a \`vendor\' tag (e. g. the authors ID):${se} ";
+ $| = 0;
+ $vtag = <>;
+ chop $vtag;
+ last if &checktag($vtag, "vendor");
+}
+
+for(;;) {
+ $| = 1;
+ print "${so}Enter a \`release\' tag (e. g. the version #):${se} ";
+ $| = 0;
+ $rtag = <>;
+ chop $rtag;
+ last if &checktag($rtag, "release");
+}
+
+
+$| = 1;
+print "${so}This is your last chance to interrupt, " .
+ "hit <return> to go on:${se} ";
+$| = 0;
+<>;
+
+$mod = "";
+foreach $tmp (@cvsmods) {
+ if($tmp gt $modname) {
+ $mod = $tmp;
+ last;
+ }
+}
+
+if($mod eq "") {
+ # we are going to append our module
+ $cmd = "\$\na\n";
+} else {
+ # we can insert it
+ $cmd = "/^${mod}[ \t]/\ni\n";
+}
+
+print "${so}Checking out the modules database...${se}\n";
+system("cvs co modules") && die "${us}failed.\n${ue}";
+
+print "${so}Inserting new module...${se}\n";
+open(ED, "|ed modules/modules") || die "${us}Cannot start ed${ue}\n";
+print(ED "${cmd}${modname}" . ' ' x (16 - length($modname)) .
+ "$area/${modpath}\n.\nw\nq\n");
+close(ED);
+
+print "${so}Commiting new modules database...${se}\n";
+system("cvs $dont_do_it commit -m \" " .
+ "${modname} --> $area/${modpath}\" modules")
+ && die "Commit failed\n";
+
+system("cvs $dont_do_it release -dQ modules");
+
+print "${so}Importing source. Enter a commit message in the editor.${se}\n";
+
+system("cvs $dont_do_it import $area/$modpath $vtag $rtag");
+
+print "${so}You are done now. Go to a different directory, perform a${se}\n".
+ "${us}cvs co ${modname}${ue} ${so}command, and see if your new module" .
+ " builds ok.${se}\n";
+
+if($dont_do_it) {
+print <<END
+
+
+${so}Since you did not allow to commit anything, you'll have${se}
+${so}to remove the edited modules' database yourself.${se}
+${so}To do this, perform a${se}
+${us}cd ${moduledir}; cvs release -dQ modules${ue}
+${so}command.${se}
+END
+;
+}
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/cookie.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/cookie.el
new file mode 100644
index 000000000000..8bd4bdff6ce0
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/cookie.el
@@ -0,0 +1,884 @@
+;;; cookie.el,v 1.2 1992/04/07 20:49:12 berliner Exp
+;;; cookie.el -- Utility to display cookies in buffers
+;;; Copyright (C) 1991, 1992 Per Cederqvist
+;;;
+;;; This program is free software; you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 2 of the License, or
+;;; (at your option) any later version.
+;;;
+;;; This program is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with this program; if not, write to the Free Software
+;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;;; TO-DO: Byt namn! tin -> wrapper (eller n}got b{ttre).
+
+;;; Note that this file is still under development. Comments,
+;;; enhancements and bug fixes are welcome.
+;;; Send them to ceder@lysator.liu.se.
+
+(defun impl nil (error "Not yet implemented!"))
+
+;;; Cookie is a package that imlements a connection between an
+;;; elib-dll and the contents of a buffer. Possible uses are dired
+;;; (have all files in a list, and show them), buffer-list,
+;;; kom-prioritize (in the LysKOM elisp client) and others. pcl-cvs.el
+;;; uses cookie.el.
+;;;
+;;; A cookie buffer contains a header, any number of cookies, and a
+;;; footer. The header and footer are constant strings that are given
+;;; to cookie-create when the buffer is placed under cookie. Each cookie
+;;; is displayed in the buffer by calling a user-supplied function
+;;; that takes a cookie and returns a string. The string may be
+;;; empty, or contain any number of lines. An extra newline is always
+;;; appended unless the string is empty.
+;;;
+;;; Cookie does not affect the mode of the buffer in any way. It
+;;; merely makes it easy to connect an underlying data representation
+;;; to the buffer contents.
+;;;
+;;; The cookie-node data type:
+;;; start-marker
+;;; ;; end-marker This field is no longer present.
+;;; cookie The user-supplied element.
+;;;
+;;; A dll of cookie-nodes are held in the buffer local variable
+;;; cake-tin.
+;;;
+;;; A tin is an object that contains one cookie. You can get the next
+;;; and previous tin.
+;;;
+
+(require 'elib-dll)
+(provide 'cookie)
+
+(defvar cookies nil
+ "A doubly linked list that contains the underlying data representation
+for the contents of a cookie buffer. The package elib-dll is used to
+manipulate this list.")
+
+(defvar cookie-pretty-printer nil
+ "The function that is used to pretty-print a cookie in this buffer.")
+
+(defvar cookie-header nil
+ "The tin that holds the header cookie.")
+
+(defvar cookie-footer nil
+ "The tin that holds the footer cookie.")
+
+(defvar cookie-last-tin nil
+ "The tin the cursor was positioned at, the last time the cookie
+package checked the cursor position. Buffer local in all buffers
+the cookie package works on. You may set this if your package
+thinks it knows where the cursor will be the next time this
+package is called. It can speed things up.
+
+It must never be set to a tin that has been deleted.")
+
+;;; ================================================================
+;;; Internal functions for use in the cookie package
+
+(put 'cookie-set-buffer 'lisp-indent-hook 1)
+
+(defmacro cookie-set-buffer (buffer &rest forms)
+
+ ;; Execute FORMS with BUFFER selected as current buffer.
+ ;; Return value of last form in FORMS. INTERNAL USE ONLY.
+
+ (let ((old-buffer (make-symbol "old-buffer")))
+ (` (let (((, old-buffer) (current-buffer)))
+ (set-buffer (get-buffer-create (, buffer)))
+ (unwind-protect
+ (progn (,@ forms))
+ (set-buffer (, old-buffer)))))))
+
+
+(defmacro cookie-filter-hf (tin)
+
+ ;; Evaluate TIN once and return it. BUT if it is
+ ;; equal to cookie-header or cookie-footer return nil instead.
+ ;; INTERNAL USE ONLY.
+
+ (let ((tempvar (make-symbol "tin")))
+ (` (let (((, tempvar) (, tin)))
+ (if (or (eq (, tempvar) cookie-header)
+ (eq (, tempvar) cookie-footer))
+ nil
+ (, tempvar))))))
+
+
+;;; cookie-tin
+;;; Constructor:
+
+(defun cookie-create-tin (start-marker
+ cookie)
+ ;; Create a tin. INTERNAL USE ONLY.
+ (cons 'COOKIE-TIN (vector start-marker nil cookie)))
+
+
+;;; Selectors:
+
+(defun cookie-tin-start-marker (cookie-tin)
+ ;; Get start-marker from cookie-tin. INTERNAL USE ONLY.
+ (elt (cdr cookie-tin) 0))
+
+;(defun cookie-tin-end-marker (cookie-tin)
+; ;;Get end-marker from cookie-tin. INTERNAL USE ONLY.
+; (elt (cdr cookie-tin) 1))
+
+(defun cookie-tin-cookie-safe (cookie-tin)
+ ;; Get cookie from cookie-tin. INTERNAL USE ONLY.
+ ;; Returns nil if given nil as input.
+ ;; This is the same as cookie-tin-cookie in version 18.57
+ ;; of emacs, but elt should signal an error when given nil
+ ;; as input (according to the info files).
+ (elt (cdr cookie-tin) 2))
+
+(defun cookie-tin-cookie (cookie-tin)
+ ;; Get cookie from cookie-tin. INTERNAL USE ONLY.
+ (elt (cdr cookie-tin) 2))
+
+
+;;; Modifiers:
+
+(defun set-cookie-tin-start-marker (cookie-tin newval)
+ ;; Set start-marker in cookie-tin to NEWVAL. INTERNAL USE ONLY.
+ (aset (cdr cookie-tin) 0 newval))
+
+;(defun set-cookie-tin-end-marker (cookie-tin newval)
+; ;; Set end-marker in cookie-tin to NEWVAL. INTERNAL USE ONLY.
+; (aset (cdr cookie-tin) 1 newval))
+
+(defun set-cookie-tin-cookie (cookie-tin newval)
+ ;; Set cookie in cookie-tin to NEWVAL. INTERNAL USE ONLY.
+ (aset (cdr cookie-tin) 2 newval))
+
+
+
+;;; Predicate:
+
+(defun cookie-tin-p (object)
+ ;; Return t if OBJECT is a tin. INTERNAL USE ONLY.
+ (eq (car-safe object) 'COOKIE-TIN))
+
+;;; end of cookie-tin data type.
+
+
+(defun cookie-create-tin-and-insert (cookie string pos)
+ ;; Insert STRING at POS in current buffer. Remember start
+ ;; position. Create a tin containing them and the COOKIE.
+ ;; INTERNAL USE ONLY.
+
+ (save-excursion
+ (goto-char pos)
+ ;; Remember the position as a number so that it doesn't move
+ ;; when we insert the string.
+ (let ((start (if (markerp pos)
+ (marker-position pos)
+ pos)))
+ ;; Use insert-before-markers so that the marker for the
+ ;; next cookie is updated.
+ (insert-before-markers string)
+ (insert-before-markers ?\n)
+ (cookie-create-tin (copy-marker start) cookie))))
+
+
+(defun cookie-delete-tin-internal (tin)
+ ;; Delete a cookie from the buffer. INTERNAL USE ONLY.
+ ;; Can not be used on the footer.
+ (delete-region (cookie-tin-start-marker (dll-element cookies tin))
+ (cookie-tin-start-marker
+ (dll-element cookies
+ (dll-next cookies tin)))))
+
+
+
+(defun cookie-refresh-tin (tin)
+ ;; Redisplay the cookie represented by TIN. INTERNAL USE ONLY.
+ ;; Can not be used on the footer.
+
+ (save-excursion
+ ;; First, remove the string:
+ (delete-region (cookie-tin-start-marker (dll-element cookies tin))
+ (1- (marker-position
+ (cookie-tin-start-marker
+ (dll-element cookies
+ (dll-next cookies tin))))))
+
+ ;; Calculate and insert the string.
+
+ (goto-char (cookie-tin-start-marker (dll-element cookies tin)))
+ (insert
+ (funcall cookie-pretty-printer
+ (cookie-tin-cookie (dll-element cookies tin))))))
+
+
+;;; ================================================================
+;;; The public members of the cookie package
+
+
+(defun cookie-cookie (buffer tin)
+ "Get the cookie from a TIN. Args: BUFFER TIN."
+ (cookie-set-buffer buffer
+ (cookie-tin-cookie (dll-element cookies tin))))
+
+
+
+
+(defun cookie-create (buffer pretty-printer &optional header footer)
+
+ "Start to use the cookie package in BUFFER.
+BUFFER may be a buffer or a buffer name. It is created if it does not exist.
+Beware that the entire contents of the buffer will be erased.
+PRETTY-PRINTER is a function that takes one cookie and returns a string
+to be displayed in the buffer. The string may be empty. If it is not
+empty a newline will be added automatically. It may span several lines.
+Optional third argument HEADER is a string that will always be present
+at the top of the buffer. HEADER should end with a newline. Optionaly
+fourth argument FOOTER is similar, and will always be inserted at the
+bottom of the buffer."
+
+ (cookie-set-buffer buffer
+
+ (erase-buffer)
+
+ (make-local-variable 'cookie-last-tin)
+ (make-local-variable 'cookie-pretty-printer)
+ (make-local-variable 'cookie-header)
+ (make-local-variable 'cookie-footer)
+ (make-local-variable 'cookies)
+
+ (setq cookie-last-tin nil)
+ (setq cookie-pretty-printer pretty-printer)
+ (setq cookies (dll-create))
+
+ (dll-enter-first cookies
+ (cookie-create-tin-and-insert
+ header header 0))
+ (setq cookie-header (dll-nth cookies 0))
+
+ (dll-enter-last cookies
+ (cookie-create-tin-and-insert
+ footer footer (point-max)))
+ (setq cookie-footer (dll-nth cookies -1))
+
+ (goto-char (point-min))
+ (forward-line 1)))
+
+
+(defun cookie-set-header (buffer header)
+ "Change the header. Args: BUFFER HEADER."
+ (impl))
+
+
+(defun cookie-set-footer (buffer header)
+ "Change the footer. Args: BUFFER FOOTER."
+ (impl))
+
+
+
+(defun cookie-enter-first (buffer cookie)
+ "Enter a COOKIE first in BUFFER.
+Args: BUFFER COOKIE."
+
+ (cookie-set-buffer buffer
+
+ ;; It is always safe to insert an element after the first element,
+ ;; because the header is always present. (dll-nth cookies 0) should
+ ;; never return nil.
+
+ (dll-enter-after
+ cookies
+ (dll-nth cookies 0)
+ (cookie-create-tin-and-insert
+ cookie
+ (funcall cookie-pretty-printer cookie)
+ (cookie-tin-start-marker
+ (dll-element cookies (dll-nth cookies 1)))))))
+
+
+
+(defun cookie-enter-last (buffer cookie)
+ "Enter a COOKIE last in BUFFER.
+Args: BUFFER COOKIE."
+
+ (cookie-set-buffer buffer
+
+ ;; Remember that the header and footer are always present. There
+ ;; is no need to check if (dll-nth cookies -2) returns nil.
+
+ (dll-enter-before
+ cookies
+ (dll-nth cookies -1)
+ (cookie-create-tin-and-insert
+ cookie
+ (funcall cookie-pretty-printer cookie)
+ (cookie-tin-start-marker (dll-last cookies))))))
+
+
+(defun cookie-enter-after (buffer node cookie)
+ (impl))
+
+
+(defun cookie-enter-before (buffer node cookie)
+ (impl))
+
+
+
+(defun cookie-next (buffer tin)
+ "Get the next tin. Args: BUFFER TIN.
+Returns nil if TIN is nil or the last cookie."
+ (if tin
+ (cookie-set-buffer buffer
+ (cookie-filter-hf (dll-next cookies tin)))))
+
+
+
+(defun cookie-previous (buffer tin)
+ "Get the previous tin. Args: BUFFER TIN.
+Returns nil if TIN is nil or the first cookie."
+ (if tin
+ (cookie-set-buffer buffer
+ (cookie-filter-hf (dll-previous cookies tin)))))
+
+
+(defun cookie-nth (buffer n)
+
+ "Return the Nth tin. Args: BUFFER N.
+N counts from zero. Nil is returned if there is less than N cookies.
+If N is negative, return the -(N+1)th last element.
+Thus, (cookie-nth dll 0) returns the first node,
+and (cookie-nth dll -1) returns the last node.
+
+Use cookie-cookie to extract the cookie from the tin."
+
+ (cookie-set-buffer buffer
+
+ ;; Skip the header (or footer, if n is negative).
+ (if (< n 0)
+ (setq n (1- n))
+ (setq n (1+ n)))
+
+ (cookie-filter-hf (dll-nth cookies n))))
+
+
+
+(defun cookie-delete (buffer tin)
+ "Delete a cookie. Args: BUFFER TIN."
+
+ (cookie-set-buffer buffer
+ (if (eq cookie-last-tin tin)
+ (setq cookie-last-tin nil))
+
+ (cookie-delete-tin-internal tin)
+ (dll-delete cookies tin)))
+
+
+
+(defun cookie-delete-first (buffer)
+ "Delete first cookie and return it. Args: BUFFER.
+Returns nil if there is no cookie left."
+
+ (cookie-set-buffer buffer
+
+ ;; We have to check that we do not try to delete the footer.
+
+ (let ((tin (dll-nth cookies 1))) ;Skip the header.
+ (if (eq tin cookie-footer)
+ nil
+ (cookie-delete-tin-internal tin)
+ (cookie-tin-cookie (dll-delete cookies tin))))))
+
+
+
+(defun cookie-delete-last (buffer)
+ "Delete last cookie and return it. Args: BUFFER.
+Returns nil if there is no cookie left."
+
+ (cookie-set-buffer buffer
+
+ ;; We have to check that we do not try to delete the header.
+
+ (let ((tin (dll-nth cookies -2))) ;Skip the footer.
+ (if (eq tin cookie-header)
+ nil
+ (cookie-delete-tin-internal tin)
+ (cookie-tin-cookie (dll-delete cookies tin))))))
+
+
+
+(defun cookie-first (buffer)
+
+ "Return the first cookie in BUFFER. The cookie is not removed."
+
+ (cookie-set-buffer buffer
+ (let ((tin (cookie-filter-hf (dll-nth cookies -1))))
+ (if tin
+ (cookie-tin-cookie-safe
+ (dll-element cookies tin))))))
+
+
+(defun cookie-last (buffer)
+
+ "Return the last cookie in BUFFER. The cookie is not removed."
+
+ (cookie-set-buffer buffer
+ (let ((tin (cookie-filter-hf (dll-nth cookies -2))))
+ (if tin
+ (cookie-tin-cookie-safe
+ (dll-element cookies tin))))))
+
+
+(defun cookie-empty (buffer)
+
+ "Return true if there are no cookies in BUFFER."
+
+ (cookie-set-buffer buffer
+ (eq (dll-nth cookies 1) cookie-footer)))
+
+
+(defun cookie-length (buffer)
+
+ "Return number of cookies in BUFFER."
+
+ ;; Don't count the footer and header.
+
+ (cookie-set-buffer buffer
+ (- (dll-length cookies) 2)))
+
+
+(defun cookie-all (buffer)
+
+ "Return a list of all cookies in BUFFER."
+
+ (cookie-set-buffer buffer
+ (let (result
+ (tin (dll-nth cookies -2)))
+ (while (not (eq tin cookie-header))
+ (setq result (cons (cookie-tin-cookie (dll-element cookies tin))
+ result))
+ (setq tin (dll-previous cookies tin)))
+ result)))
+
+(defun cookie-clear (buffer)
+
+ "Remove all cookies in buffer."
+
+ (cookie-set-buffer buffer
+ (cookie-create buffer cookie-pretty-printer
+ (cookie-tin-cookie (dll-element cookies cookie-header))
+ (cookie-tin-cookie (dll-element cookies cookie-footer)))))
+
+
+
+(defun cookie-map (map-function buffer &rest map-args)
+
+ "Apply MAP-FUNCTION to all cookies in BUFFER.
+MAP-FUNCTION is applied to the first element first.
+If MAP-FUNCTION returns non-nil the cookie will be refreshed.
+
+Note that BUFFER will be current buffer when MAP-FUNCTION is called.
+
+If more than two arguments are given to cookie-map, remaining
+arguments will be passed to MAP-FUNCTION."
+
+ (cookie-set-buffer buffer
+ (let ((tin (dll-nth cookies 1))
+ result)
+
+ (while (not (eq tin cookie-footer))
+
+ (if (apply map-function
+ (cookie-tin-cookie (dll-element cookies tin))
+ map-args)
+ (cookie-refresh-tin tin))
+
+ (setq tin (dll-next cookies tin))))))
+
+
+
+(defun cookie-map-reverse (map-function buffer &rest map-args)
+
+ "Apply MAP-FUNCTION to all cookies in BUFFER.
+MAP-FUNCTION is applied to the last cookie first.
+If MAP-FUNCTION returns non-nil the cookie will be refreshed.
+
+Note that BUFFER will be current buffer when MAP-FUNCTION is called.
+
+If more than two arguments are given to cookie-map, remaining
+arguments will be passed to MAP-FUNCTION."
+
+ (cookie-set-buffer buffer
+ (let ((tin (dll-nth cookies -2))
+ result)
+
+ (while (not (eq tin cookie-header))
+
+ (if (apply map-function
+ (cookie-tin-cookie (dll-element cookies tin))
+ map-args)
+ (cookie-refresh-tin tin))
+
+ (setq tin (dll-previous cookies tin))))))
+
+
+
+(defun cookie-enter-cookies (buffer cookie-list)
+
+ "Insert all cookies in the list COOKIE-LIST last in BUFFER.
+Args: BUFFER COOKIE-LIST."
+
+ (while cookie-list
+ (cookie-enter-last buffer (car cookie-list))
+ (setq cookie-list (cdr cookie-list))))
+
+
+(defun cookie-filter (buffer predicate)
+
+ "Remove all cookies in BUFFER for which PREDICATE returns nil.
+Note that BUFFER will be current-buffer when PREDICATE is called.
+
+The PREDICATE is called with one argument, the cookie."
+
+ (cookie-set-buffer buffer
+ (let ((tin (dll-nth cookies 1))
+ next)
+ (while (not (eq tin cookie-footer))
+ (setq next (dll-next cookies tin))
+ (if (funcall predicate (cookie-tin-cookie (dll-element cookies tin)))
+ nil
+ (cookie-delete-tin-internal tin)
+ (dll-delete cookies tin))
+ (setq tin next)))))
+
+
+(defun cookie-filter-tins (buffer predicate)
+
+ "Remove all cookies in BUFFER for which PREDICATE returns nil.
+Note that BUFFER will be current-buffer when PREDICATE is called.
+
+The PREDICATE is called with one argument, the tin."
+
+ (cookie-set-buffer buffer
+ (let ((tin (dll-nth cookies 1))
+ next)
+ (while (not (eq tin cookie-footer))
+ (setq next (dll-next cookies tin))
+ (if (funcall predicate tin)
+ nil
+ (cookie-delete-tin-internal tin)
+ (dll-delete cookies tin))
+ (setq tin next)))))
+
+(defun cookie-pos-before-middle-p (pos tin1 tin2)
+
+ "Return true if POS is in the first half of the region defined by TIN1 and
+TIN2."
+
+ (< pos (/ (+ (cookie-tin-start-marker (dll-element cookeis tin1))
+ (cookie-tin-start-marker (dll-element cookeis tin2)))
+ 2)))
+
+
+(defun cookie-get-selection (buffer pos &optional guess force-guess)
+
+ "Return the tin the POS is within.
+Args: BUFFER POS &optional GUESS FORCE-GUESS.
+GUESS should be a tin that it is likely that POS is near. If FORCE-GUESS
+is non-nil GUESS is always used as a first guess, otherwise the first
+guess is the first tin, last tin, or GUESS, whichever is nearest to
+pos in the BUFFER.
+
+If pos points within the header, the first cookie is returned.
+If pos points within the footer, the last cookie is returned.
+Nil is returned if there is no cookie.
+
+It is often good to specify cookie-last-tin as GUESS, but remember
+that cookie-last-tin is buffer local in all buffers that cookie
+operates on."
+
+ (cookie-set-buffer buffer
+
+ (cond
+ ; No cookies present?
+ ((eq (dll-nth cookies 1) (dll-nth cookies -1))
+ nil)
+
+ ; Before first cookie?
+ ((< pos (cookie-tin-start-marker
+ (dll-element cookies (dll-nth cookies 1))))
+ (dll-nth cookies 1))
+
+ ; After last cookie?
+ ((>= pos (cookie-tin-start-marker (dll-last cookies)))
+ (dll-nth cookies -2))
+
+ ; We now now that pos is within a cookie.
+ (t
+ ; Make an educated guess about which of the three known
+ ; cookies (the first, the last, or GUESS) is nearest.
+ (setq
+ guess
+ (cond
+ (force-guess guess)
+ (guess
+ (cond
+ ;; Closest to first cookie?
+ ((cookie-pos-before-middle-p
+ pos guess
+ (dll-nth cookies 1))
+ (dll-nth cookies 1))
+ ;; Closest to GUESS?
+ ((cookie-pos-before-middle-p
+ pos guess
+ cookie-footer)
+ guess)
+ ;; Closest to last cookie.
+ (t (dll-previous cookies cookie-footer))))
+ (t
+ ;; No guess given.
+ (cond
+ ;; First half?
+ ((cookie-pos-before-middle-p
+ pos (dll-nth cookies 1)
+ cookie-footer)
+ (dll-nth cookies 1))
+ (t (dll-previous cookies cookie-footer))))))
+
+ ;; GUESS is now a "best guess".
+
+ ;; Find the correct cookie. First determine in which direction
+ ;; it lies, and then move in that direction until it is found.
+
+ (cond
+ ;; Is pos after the guess?
+ ((>= pos (cookie-tin-start-marker (dll-element cookiess guess)))
+
+ ;; Loop until we are exactly one cookie too far down...
+ (while (>= pos (cookie-tin-start-marker (dll-element cookiess guess)))
+ (setq guess (dll-next cookies guess)))
+
+ ;; ...and return the previous cookie.
+ (dll-previous cookies guess))
+
+ ;; Pos is before guess
+ (t
+
+ (while (< pos (cookie-tin-start-marker (dll-element cookiess guess)))
+ (setq guess (dll-previous cookies guess)))
+
+ guess))))))
+
+
+(defun cookie-start-marker (buffer tin)
+
+ "Return start-position of a cookie in BUFFER.
+Args: BUFFER TIN.
+The marker that is returned should not be modified in any way,
+and is only valid until the contents of the cookie buffer changes."
+
+ (cookie-set-buffer buffer
+ (cookie-tin-start-marker (dll-element cookies tin))))
+
+
+(defun cookie-end-marker (buffer tin)
+
+ "Return end-position of a cookie in BUFFER.
+Args: BUFFER TIN.
+The marker that is returned should not be modified in any way,
+and is only valid until the contents of the cookie buffer changes."
+
+ (cookie-set-buffer buffer
+ (cookie-tin-start-marker
+ (dll-element cookies (dll-next cookies tin)))))
+
+
+
+(defun cookie-refresh (buffer)
+
+ "Refresh all cookies in BUFFER.
+Cookie-pretty-printer will be called for all cookies and the new result
+displayed.
+
+See also cookie-invalidate-tins."
+
+ (cookie-set-buffer buffer
+
+ (erase-buffer)
+
+ (set-marker (cookie-tin-start-marker (dll-element cookies cookie-header))
+ (point) buffer)
+ (insert (cookie-tin-cookie (dll-element cookies cookie-header)))
+ (insert "\n")
+
+ (let ((tin (dll-nth cookies 1)))
+ (while (not (eq tin cookie-footer))
+
+ (set-marker (cookie-tin-start-marker (dll-element cookies tin))
+ (point) buffer)
+ (insert
+ (funcall cookie-pretty-printer
+ (cookie-tin-cookie (dll-element cookies tin))))
+ (insert "\n")
+ (setq tin (dll-next cookies tin))))
+
+ (set-marker (cookie-tin-start-marker (dll-element cookies cookie-footer))
+ (point) buffer)
+ (insert (cookie-tin-cookie (dll-element cookies cookie-footer)))
+ (insert "\n")))
+
+
+(defun cookie-invalidate-tins (buffer &rest tins)
+
+ "Refresh some cookies.
+Args: BUFFER &rest TINS."
+
+ (cookie-set-buffer buffer
+
+ (while tins
+ (cookie-refresh-tin (car tins))
+ (setq tins (cdr tins)))))
+
+
+;;; Cookie movement commands.
+
+(defun cookie-set-goal-column (buffer goal)
+ "Set goal-column for BUFFER.
+Args: BUFFER GOAL.
+goal-column is made buffer-local."
+ (cookie-set-buffer buffer
+ (make-local-variable 'goal-column)
+ (setq goal-column goal)))
+
+
+(defun cookie-previous-cookie (buffer pos arg)
+ "Move point to the ARGth previous cookie.
+Don't move if we are at the first cookie.
+ARG is the prefix argument when called interactively.
+Args: BUFFER POS ARG.
+Sets cookie-last-tin to the cookie we move to."
+
+ (interactive (list (current-buffer) (point)
+ (prefix-numeric-value current-prefix-arg)))
+
+ (cookie-set-buffer buffer
+ (setq cookie-last-tin
+ (cookie-get-selection buffer pos cookie-last-tin))
+
+ (while (and cookie-last-tin (> arg 0))
+ (setq arg (1- arg))
+ (setq cookie-last-tin
+ (dll-previous cookies cookie-last-tin)))
+
+ ;; Never step above the first cookie.
+
+ (if (null (cookie-filter-hf cookie-last-tin))
+ (setq cookie-last-tin (dll-nth cookies 1)))
+
+ (goto-char
+ (cookie-tin-start-marker
+ (dll-element cookies cookie-last-tin)))
+
+ (if goal-column
+ (move-to-column goal-column))))
+
+
+
+(defun cookie-next-cookie (buffer pos arg)
+ "Move point to the ARGth next cookie.
+Don't move if we are at the last cookie.
+ARG is the prefix argument when called interactively.
+Args: BUFFER POS ARG.
+Sets cookie-last-tin to the cookie we move to."
+
+ (interactive (list (current-buffer) (point)
+ (prefix-numeric-value current-prefix-arg)))
+
+ (cookie-set-buffer buffer
+ (setq cookie-last-tin
+ (cookie-get-selection buffer pos cookie-last-tin))
+
+ (while (and cookie-last-tin (> arg 0))
+ (setq arg (1- arg))
+ (setq cookie-last-tin
+ (dll-next cookies cookie-last-tin)))
+
+ (if (null (cookie-filter-hf cookie-last-tin))
+ (setq cookie-last-tin (dll-nth cookies -2)))
+
+ (goto-char
+ (cookie-tin-start-marker
+ (dll-element cookies cookie-last-tin)))
+
+ (if goal-column
+ (move-to-column goal-column))))
+
+
+(defun cookie-collect-tins (buffer predicate &rest predicate-args)
+
+ "Return a list of all tins in BUFFER whose cookie PREDICATE
+returns true for.
+PREDICATE is a function that takes a cookie as its argument.
+The tins on the returned list will appear in the same order
+as in the buffer. You should not rely on in which order PREDICATE
+is called. Note that BUFFER is current-buffer when PREDICATE
+is called. (If you call cookie-collect with another buffer set
+as current-buffer and need to access buffer-local variables
+from that buffer within PREDICATE you must send them via
+PREDICATE-ARGS).
+
+If more than two arguments are given to cookie-collect the remaining
+arguments will be passed to PREDICATE.
+
+Use cookie-cookie to get the cookie from the tin."
+
+ (cookie-set-buffer buffer
+ (let ((tin (dll-nth cookies -2))
+ result)
+
+ (while (not (eq tin cookie-header))
+
+ (if (apply predicate
+ (cookie-tin-cookie (dll-element cookies tin))
+ predicate-args)
+ (setq result (cons tin result)))
+
+ (setq tin (dll-previous cookies tin)))
+ result)))
+
+
+(defun cookie-collect-cookies (buffer predicate &rest predicate-args)
+
+ "Return a list of all cookies in BUFFER that PREDICATE
+returns true for.
+PREDICATE is a function that takes a cookie as its argument.
+The cookie on the returned list will appear in the same order
+as in the buffer. You should not rely on in which order PREDICATE
+is called. Note that BUFFER is current-buffer when PREDICATE
+is called. (If you call cookie-collect with another buffer set
+as current-buffer and need to access buffer-local variables
+from that buffer within PREDICATE you must send them via
+PREDICATE-ARGS).
+
+If more than two arguments are given to cookie-collect the remaining
+arguments will be passed to PREDICATE."
+
+ (cookie-set-buffer buffer
+ (let ((tin (dll-nth cookies -2))
+ result)
+
+ (while (not (eq tin cookie-header))
+
+ (if (apply predicate
+ (cookie-tin-cookie (dll-element cookies tin))
+ predicate-args)
+ (setq result (cons (cookie-tin-cookie (dll-element cookies tin))
+ result)))
+
+ (setq tin (dll-previous cookies tin)))
+ result)))
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll-debug.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll-debug.el
new file mode 100644
index 000000000000..733ff86f46c0
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll-debug.el
@@ -0,0 +1,298 @@
+;;; elib-dll-debug -- A slow implementation of elib-dll for debugging.
+;;; elib-dll-debug.el,v 1.2 1992/04/07 20:49:13 berliner Exp
+;;; Copyright (C) 1991,1992 Per Cederqvist
+;;;
+;;; This program is free software; you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 2 of the License, or
+;;; (at your option) any later version.
+;;;
+;;; This program is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with this program; if not, write to the Free Software
+;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+;;; This is a plug-in replacement for elib-dll.el. It is dreadfully
+;;; slow, but it facilitates debugging. Don't trust the comments in
+;;; this file too much.
+(provide 'elib-dll)
+
+;;;
+;;; A doubly linked list consists of one cons cell which holds the tag
+;;; 'DL-LIST in the car cell and the list in the cdr
+;;; cell. The doubly linked list is implemented as a normal list. You
+;;; should use elib-dll.el and not this package in debugged code. This
+;;; package is not written for speed...
+;;;
+
+;;; ================================================================
+;;; Internal functions for use in the doubly linked list package
+
+(defun dll-get-dummy-node (dll)
+
+ ;; Return the dummy node. INTERNAL USE ONLY.
+ dll)
+
+(defun dll-list-nodes (dll)
+
+ ;; Return a list of all nodes in DLL. INTERNAL USE ONLY.
+
+ (cdr dll))
+
+(defun dll-set-from-node-list (dll list)
+
+ ;; Set the contents of DLL to the nodes in LIST.
+ ;; INTERNAL USE ONLY.
+
+ (setcdr dll list))
+
+(defun dll-get-node-before (dll node)
+ ;; Return the node in DLL that points to NODE. Use
+ ;; (dll-get-node-before some-list nil) to get the last node.
+ ;; INTERNAL USE ONLY.
+ (while (and dll (not (eq (cdr dll) node)))
+ (setq dll (cdr dll)))
+ (if (not dll)
+ (error "Node not on list"))
+ dll)
+
+(defmacro dll-insert-after (node element)
+ (let ((node-v (make-symbol "node"))
+ (element-v (make-symbol "element")))
+ (` (let (((, node-v) (, node))
+ ((, element-v) (, element)))
+ (setcdr (, node-v) (cons (, element-v) (cdr (, node-v))))))))
+
+;;; ===================================================================
+;;; The public functions which operate on doubly linked lists.
+
+(defmacro dll-element (dll node)
+
+ "Get the element of a NODE in a doubly linked list DLL.
+Args: DLL NODE."
+
+ (` (car (, node))))
+
+
+(defun dll-create ()
+ "Create an empty doubly linked list."
+ (cons 'DL-LIST nil))
+
+
+(defun dll-p (object)
+ "Return t if OBJECT is a doubly linked list, otherwise return nil."
+ (eq (car-safe object) 'DL-LIST))
+
+
+(defun dll-enter-first (dll element)
+ "Add an element first on a doubly linked list.
+Args: DLL ELEMENT."
+ (setcdr dll (cons element (cdr dll))))
+
+
+(defun dll-enter-last (dll element)
+ "Add an element last on a doubly linked list.
+Args: DLL ELEMENT."
+ (dll-insert-after (dll-get-node-before dll nil) element))
+
+
+(defun dll-enter-after (dll node element)
+ "In the doubly linked list DLL, insert a node containing ELEMENT after NODE.
+Args: DLL NODE ELEMENT."
+
+ (dll-get-node-before dll node)
+ (dll-insert-after node element))
+
+
+(defun dll-enter-before (dll node element)
+ "In the doubly linked list DLL, insert a node containing ELEMENT before NODE.
+Args: DLL NODE ELEMENT."
+
+ (dll-insert-after (dll-get-node-before dll node) element))
+
+
+
+(defun dll-next (dll node)
+ "Return the node after NODE, or nil if NODE is the last node.
+Args: DLL NODE."
+
+ (dll-get-node-before dll node)
+ (cdr node))
+
+
+(defun dll-previous (dll node)
+ "Return the node before NODE, or nil if NODE is the first node.
+Args: DLL NODE."
+
+ (dll-get-node-before dll node))
+
+
+(defun dll-delete (dll node)
+
+ "Delete NODE from the doubly linked list DLL.
+Args: DLL NODE. Return the element of node."
+
+ ;; This is a no-op when applied to the dummy node. This will return
+ ;; nil if applied to the dummy node since it always contains nil.
+
+ (setcdr (dll-get-node-before dll node) (cdr node)))
+
+
+(defun dll-delete-first (dll)
+
+ "Delete the first NODE from the doubly linked list DLL.
+Return the element. Args: DLL. Returns nil if the DLL was empty."
+
+ ;; Relies on the fact that dll-delete does nothing and
+ ;; returns nil if given the dummy node.
+
+ (setcdr dll (cdr (cdr dll))))
+
+
+(defun dll-delete-last (dll)
+
+ "Delete the last NODE from the doubly linked list DLL.
+Return the element. Args: DLL. Returns nil if the DLL was empty."
+
+ ;; Relies on the fact that dll-delete does nothing and
+ ;; returns nil if given the dummy node.
+
+ (setcdr dll (dll-get-node-before dll nil) nil))
+
+
+(defun dll-first (dll)
+
+ "Return the first element on the doubly linked list DLL.
+Return nil if the list is empty. The element is not removed."
+
+ (car (cdr dll)))
+
+
+
+
+(defun dll-last (dll)
+
+ "Return the last element on the doubly linked list DLL.
+Return nil if the list is empty. The element is not removed."
+
+ (car (dll-get-node-before dll nil)))
+
+
+
+(defun dll-nth (dll n)
+
+ "Return the Nth node from the doubly linked list DLL.
+ Args: DLL N
+N counts from zero. If DLL is not that long, nil is returned.
+If N is negative, return the -(N+1)th last element.
+Thus, (dll-nth dll 0) returns the first node,
+and (dll-nth dll -1) returns the last node."
+
+ ;; Branch 0 ("follow left pointer") is used when n is negative.
+ ;; Branch 1 ("follow right pointer") is used otherwise.
+
+ (if (>= n 0)
+ (nthcdr n (cdr dll))
+ (unwind-protect
+ (progn (setcdr dll (nreverse (cdr dll)))
+ (nthcdr (- n) dll))
+ (setcdr dll (nreverse (cdr dll))))))
+
+(defun dll-empty (dll)
+
+ "Return t if the doubly linked list DLL is empty, nil otherwise"
+
+ (not (cdr dll)))
+
+(defun dll-length (dll)
+
+ "Returns the number of elements in the doubly linked list DLL."
+
+ (length (cdr dll)))
+
+
+
+(defun dll-copy (dll &optional element-copy-fnc)
+
+ "Return a copy of the doubly linked list DLL.
+If optional second argument ELEMENT-COPY-FNC is non-nil it should be
+a function that takes one argument, an element, and returns a copy of it.
+If ELEMENT-COPY-FNC is not given the elements are not copied."
+
+ (if element-copy-fnc
+ (cons 'DL-LIST (mapcar element-copy-fnc (cdr dll)))
+ (copy-sequence dll)))
+
+
+(defun dll-all (dll)
+
+ "Return all elements on the double linked list DLL as an ordinary list."
+
+ (cdr dll))
+
+
+(defun dll-clear (dll)
+
+ "Clear the doubly linked list DLL, i.e. make it completely empty."
+
+ (setcdr dll nil))
+
+
+(defun dll-map (map-function dll)
+
+ "Apply MAP-FUNCTION to all elements in the doubly linked list DLL.
+The function is applied to the first element first."
+
+ (mapcar map-function (cdr dll)))
+
+
+(defun dll-map-reverse (map-function dll)
+
+ "Apply MAP-FUNCTION to all elements in the doubly linked list DLL.
+The function is applied to the last element first."
+
+ (unwind-protect
+ (setcdr dll (nreverse (cdr dll)))
+ (mapcar map-function (cdr dll))
+ (setcdr dll (nreverse (cdr dll)))))
+
+
+(defun dll-create-from-list (list)
+
+ "Given an elisp LIST create a doubly linked list with the same elements."
+
+ (cons 'DL-LIST list))
+
+
+
+(defun dll-sort (dll predicate)
+
+ "Sort the doubly linked list DLL, stably, comparing elements using PREDICATE.
+Returns the sorted list. DLL is modified by side effects.
+PREDICATE is called with two elements of DLL, and should return T
+if the first element is \"less\" than the second."
+
+ (setcdr dll (sort (cdr dll) predicate))
+ dll)
+
+
+(defun dll-filter (dll predicate)
+
+ "Remove all elements in the doubly linked list DLL for which PREDICATE
+return nil."
+
+ (let* ((prev dll)
+ (node (cdr dll)))
+
+ (while node
+ (cond
+ ((funcall predicate (car node))
+ (setq prev node))
+ (t
+ (setcdr prev (cdr node))))
+ (setq node (cdr node)))))
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll.el
new file mode 100644
index 000000000000..855bd19e8ee0
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll.el
@@ -0,0 +1,386 @@
+;;; elib-dll.el,v 1.2 1992/04/07 20:49:15 berliner Exp
+;;; elib-dll.el -- Some primitives for Doubly linked lists.
+;;; Copyright (C) 1991, 1992 Per Cederqvist
+;;;
+;;; This program is free software; you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 2 of the License, or
+;;; (at your option) any later version.
+;;;
+;;; This program is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with this program; if not, write to the Free Software
+;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Mail bug reports to ceder@lysator.liu.se.
+
+(require 'elib-node)
+(provide 'elib-dll)
+
+;;;
+;;; A doubly linked list consists of one cons cell which holds the tag
+;;; 'DL-LIST in the car cell and a pointer to a dummy node in the cdr
+;;; cell. The doubly linked list is implemented as a circular list
+;;; with the dummy node first and last. The dummy node is recognized
+;;; by comparing it to the node which the cdr of the cons cell points
+;;; to.
+;;;
+
+;;; ================================================================
+;;; Internal functions for use in the doubly linked list package
+
+(defun dll-get-dummy-node (dll)
+
+ ;; Return the dummy node. INTERNAL USE ONLY.
+ (cdr dll))
+
+(defun dll-list-nodes (dll)
+
+ ;; Return a list of all nodes in DLL. INTERNAL USE ONLY.
+
+ (let* ((result nil)
+ (dummy (dll-get-dummy-node dll))
+ (node (elib-node-left dummy)))
+
+ (while (not (eq node dummy))
+ (setq result (cons node result))
+ (setq node (elib-node-left node)))
+
+ result))
+
+(defun dll-set-from-node-list (dll list)
+
+ ;; Set the contents of DLL to the nodes in LIST.
+ ;; INTERNAL USE ONLY.
+
+ (dll-clear dll)
+ (let* ((dummy (dll-get-dummy-node dll))
+ (left dummy))
+ (while list
+ (elib-node-set-left (car list) left)
+ (elib-node-set-right left (car list))
+ (setq left (car list))
+ (setq list (cdr list)))
+
+ (elib-node-set-right left dummy)
+ (elib-node-set-left dummy left)))
+
+
+;;; ===================================================================
+;;; The public functions which operate on doubly linked lists.
+
+(defmacro dll-element (dll node)
+
+ "Get the element of a NODE in a doubly linked list DLL.
+Args: DLL NODE."
+
+ (` (elib-node-data (, node))))
+
+
+(defun dll-create ()
+ "Create an empty doubly linked list."
+ (let ((dummy-node (elib-node-create nil nil nil)))
+ (elib-node-set-right dummy-node dummy-node)
+ (elib-node-set-left dummy-node dummy-node)
+ (cons 'DL-LIST dummy-node)))
+
+(defun dll-p (object)
+ "Return t if OBJECT is a doubly linked list, otherwise return nil."
+ (eq (car-safe object) 'DL-LIST))
+
+(defun dll-enter-first (dll element)
+ "Add an element first on a doubly linked list.
+Args: DLL ELEMENT."
+ (dll-enter-after
+ dll
+ (dll-get-dummy-node dll)
+ element))
+
+
+(defun dll-enter-last (dll element)
+ "Add an element last on a doubly linked list.
+Args: DLL ELEMENT."
+ (dll-enter-before
+ dll
+ (dll-get-dummy-node dll)
+ element))
+
+
+(defun dll-enter-after (dll node element)
+ "In the doubly linked list DLL, insert a node containing ELEMENT after NODE.
+Args: DLL NODE ELEMENT."
+
+ (let ((new-node (elib-node-create
+ node (elib-node-right node)
+ element)))
+ (elib-node-set-left (elib-node-right node) new-node)
+ (elib-node-set-right node new-node)))
+
+
+(defun dll-enter-before (dll node element)
+ "In the doubly linked list DLL, insert a node containing ELEMENT before NODE.
+Args: DLL NODE ELEMENT."
+
+ (let ((new-node (elib-node-create
+ (elib-node-left node) node
+ element)))
+ (elib-node-set-right (elib-node-left node) new-node)
+ (elib-node-set-left node new-node)))
+
+
+
+(defun dll-next (dll node)
+ "Return the node after NODE, or nil if NODE is the last node.
+Args: DLL NODE."
+
+ (if (eq (elib-node-right node) (dll-get-dummy-node dll))
+ nil
+ (elib-node-right node)))
+
+
+(defun dll-previous (dll node)
+ "Return the node before NODE, or nil if NODE is the first node.
+Args: DLL NODE."
+
+ (if (eq (elib-node-left node) (dll-get-dummy-node dll))
+ nil
+ (elib-node-left node)))
+
+
+(defun dll-delete (dll node)
+
+ "Delete NODE from the doubly linked list DLL.
+Args: DLL NODE. Return the element of node."
+
+ ;; This is a no-op when applied to the dummy node. This will return
+ ;; nil if applied to the dummy node since it always contains nil.
+
+ (elib-node-set-right (elib-node-left node) (elib-node-right node))
+ (elib-node-set-left (elib-node-right node) (elib-node-left node))
+ (dll-element dll node))
+
+
+
+(defun dll-delete-first (dll)
+
+ "Delete the first NODE from the doubly linked list DLL.
+Return the element. Args: DLL. Returns nil if the DLL was empty."
+
+ ;; Relies on the fact that dll-delete does nothing and
+ ;; returns nil if given the dummy node.
+
+ (dll-delete dll (elib-node-right (dll-get-dummy-node dll))))
+
+
+(defun dll-delete-last (dll)
+
+ "Delete the last NODE from the doubly linked list DLL.
+Return the element. Args: DLL. Returns nil if the DLL was empty."
+
+ ;; Relies on the fact that dll-delete does nothing and
+ ;; returns nil if given the dummy node.
+
+ (dll-delete dll (elib-node-left (dll-get-dummy-node dll))))
+
+
+(defun dll-first (dll)
+
+ "Return the first element on the doubly linked list DLL.
+Return nil if the list is empty. The element is not removed."
+
+ (if (eq (elib-node-right (dll-get-dummy-node dll))
+ (dll-get-dummy-node dll))
+ nil
+ (elib-node-data (elib-node-right (dll-get-dummy-node dll)))))
+
+
+
+
+(defun dll-last (dll)
+
+ "Return the last element on the doubly linked list DLL.
+Return nil if the list is empty. The element is not removed."
+
+ (if (eq (elib-node-left (dll-get-dummy-node dll))
+ (dll-get-dummy-node dll))
+ nil
+ (elib-node-data (elib-node-left (dll-get-dummy-node dll)))))
+
+
+
+(defun dll-nth (dll n)
+
+ "Return the Nth node from the doubly linked list DLL.
+ Args: DLL N
+N counts from zero. If DLL is not that long, nil is returned.
+If N is negative, return the -(N+1)th last element.
+Thus, (dll-nth dll 0) returns the first node,
+and (dll-nth dll -1) returns the last node."
+
+ ;; Branch 0 ("follow left pointer") is used when n is negative.
+ ;; Branch 1 ("follow right pointer") is used otherwise.
+
+ (let* ((dummy (dll-get-dummy-node dll))
+ (branch (if (< n 0) 0 1))
+ (node (elib-node-branch dummy branch)))
+
+ (if (< n 0)
+ (setq n (- -1 n)))
+
+ (while (and (not (eq dummy node))
+ (> n 0))
+ (setq node (elib-node-branch node branch))
+ (setq n (1- n)))
+
+ (if (eq dummy node)
+ nil
+ node)))
+
+
+(defun dll-empty (dll)
+
+ "Return t if the doubly linked list DLL is empty, nil otherwise"
+
+ (eq (elib-node-left (dll-get-dummy-node dll))
+ (dll-get-dummy-node dll)))
+
+(defun dll-length (dll)
+
+ "Returns the number of elements in the doubly linked list DLL."
+
+ (let* ((dummy (dll-get-dummy-node dll))
+ (node (elib-node-right dummy))
+ (n 0))
+
+ (while (not (eq node dummy))
+ (setq node (elib-node-right node))
+ (setq n (1+ n)))
+
+ n))
+
+
+
+(defun dll-copy (dll &optional element-copy-fnc)
+
+ "Return a copy of the doubly linked list DLL.
+If optional second argument ELEMENT-COPY-FNC is non-nil it should be
+a function that takes one argument, an element, and returns a copy of it.
+If ELEMENT-COPY-FNC is not given the elements are not copied."
+
+ (let ((result (dll-create))
+ (node (dll-nth dll 0)))
+ (if element-copy-fnc
+
+ ;; Copy the elements with the user-supplied function.
+ (while node
+ (dll-enter-last result
+ (funcall element-copy-fnc
+ (dll-element dll node)))
+ (setq node (dll-next dll node)))
+
+ ;; Don't try to copy the elements - they might be
+ ;; circular lists, or anything at all...
+ (while node
+ (dll-enter-last result (dll-element dll node))
+ (setq node (dll-next dll node))))
+
+ result))
+
+
+
+(defun dll-all (dll)
+
+ "Return all elements on the double linked list DLL as an ordinary list."
+
+ (let* ((result nil)
+ (dummy (dll-get-dummy-node dll))
+ (node (elib-node-left dummy)))
+
+ (while (not (eq node dummy))
+ (setq result (cons (dll-element dll node) result))
+ (setq node (elib-node-left node)))
+
+ result))
+
+
+(defun dll-clear (dll)
+
+ "Clear the doubly linked list DLL, i.e. make it completely empty."
+
+ (elib-node-set-left (dll-get-dummy-node dll) (dll-get-dummy-node dll))
+ (elib-node-set-right (dll-get-dummy-node dll) (dll-get-dummy-node dll)))
+
+
+(defun dll-map (map-function dll)
+
+ "Apply MAP-FUNCTION to all elements in the doubly linked list DLL.
+The function is applied to the first element first."
+
+ (let* ((dummy (dll-get-dummy-node dll))
+ (node (elib-node-right dummy)))
+
+ (while (not (eq node dummy))
+ (funcall map-function (dll-element dll node))
+ (setq node (elib-node-right node)))))
+
+
+(defun dll-map-reverse (map-function dll)
+
+ "Apply MAP-FUNCTION to all elements in the doubly linked list DLL.
+The function is applied to the last element first."
+
+ (let* ((dummy (dll-get-dummy-node dll))
+ (node (elib-node-left dummy)))
+
+ (while (not (eq node dummy))
+ (funcall map-function (dll-element dll node))
+ (setq node (elib-node-left node)))))
+
+
+(defun dll-create-from-list (list)
+
+ "Given an elisp LIST create a doubly linked list with the same elements."
+
+ (let ((dll (dll-create)))
+ (while list
+ (dll-enter-last dll (car list))
+ (setq list (cdr list)))
+ dll))
+
+
+
+(defun dll-sort (dll predicate)
+
+ "Sort the doubly linked list DLL, stably, comparing elements using PREDICATE.
+Returns the sorted list. DLL is modified by side effects.
+PREDICATE is called with two elements of DLL, and should return T
+if the first element is \"less\" than the second."
+
+ (dll-set-from-node-list
+ dll (sort (dll-list-nodes dll)
+ (function (lambda (x1 x2)
+ (funcall predicate
+ (dll-element dll x1)
+ (dll-element dll x2))))))
+ dll)
+
+
+(defun dll-filter (dll predicate)
+
+ "Remove all elements in the doubly linked list DLL for which PREDICATE
+return nil."
+
+ (let* ((dummy (dll-get-dummy-node dll))
+ (node (elib-node-right dummy))
+ next)
+
+ (while (not (eq node dummy))
+ (setq next (elib-node-right node))
+ (if (funcall predicate (dll-element dll node))
+ nil
+ (dll-delete dll node))
+ (setq node next))))
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-node.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-node.el
new file mode 100644
index 000000000000..6c476a35ef3d
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-node.el
@@ -0,0 +1,89 @@
+;;;; elib-node.el,v 1.2 1992/04/07 20:49:16 berliner Exp
+;;;; This file implements the nodes used in binary trees and
+;;;; doubly linked lists
+;;;;
+;;;; Copyright (C) 1991 Inge Wallin
+;;;;
+;;;; This file is part of the GNU Emacs lisp library, Elib.
+;;;;
+;;;; GNU Elib is free software; you can redistribute it and/or modify
+;;;; it under the terms of the GNU General Public License as published by
+;;;; the Free Software Foundation; either version 1, or (at your option)
+;;;; any later version.
+;;;;
+;;;; GNU Elib is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;;; GNU General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU General Public License
+;;;; along with GNU Emacs; see the file COPYING. If not, write to
+;;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+;;;;
+;;;; Author: Inge Wallin
+;;;;
+
+;;;
+;;; A node is implemented as an array with three elements, using
+;;; (elt node 0) as the left pointer
+;;; (elt node 1) as the right pointer
+;;; (elt node 2) as the data
+;;;
+;;; Some types of trees, e.g. AVL trees, need bigger nodes, but
+;;; as long as the first three parts are the left pointer, the
+;;; right pointer and the data field, these macros can be used.
+;;;
+
+
+(provide 'elib-node)
+
+
+(defmacro elib-node-create (left right data)
+ "Create a tree node from LEFT, RIGHT and DATA."
+ (` (vector (, left) (, right) (, data))))
+
+
+(defmacro elib-node-left (node)
+ "Return the left pointer of NODE."
+ (` (aref (, node) 0)))
+
+
+(defmacro elib-node-right (node)
+ "Return the right pointer of NODE."
+ (` (aref (, node) 1)))
+
+
+(defmacro elib-node-data (node)
+ "Return the data of NODE."
+ (` (aref (, node) 2)))
+
+
+(defmacro elib-node-set-left (node newleft)
+ "Set the left pointer of NODE to NEWLEFT."
+ (` (aset (, node) 0 (, newleft))))
+
+
+(defmacro elib-node-set-right (node newright)
+ "Set the right pointer of NODE to NEWRIGHT."
+ (` (aset (, node) 1 (, newright))))
+
+
+(defmacro elib-node-set-data (node newdata)
+ "Set the data of NODE to NEWDATA."
+ (` (aset (, node) 2 (, newdata))))
+
+
+
+(defmacro elib-node-branch (node branch)
+ "Get value of a branch of a node.
+NODE is the node, and BRANCH is the branch.
+0 for left pointer, 1 for right pointer and 2 for the data."
+ (` (aref (, node) (, branch))))
+
+
+(defmacro elib-node-set-branch (node branch newval)
+ "Set value of a branch of a node.
+NODE is the node, and BRANCH is the branch.
+0 for left pointer, 1 for the right pointer and 2 for the data.
+NEWVAL is new value of the branch."
+ (` (aset (, node) (, branch) (, newval))))
diff --git a/gnu/usr.bin/cvs/contrib/rcs-to-cvs b/gnu/usr.bin/cvs/contrib/rcs-to-cvs
new file mode 100644
index 000000000000..5863ed87414c
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/rcs-to-cvs
@@ -0,0 +1,184 @@
+#!/bin/sh
+#
+# $Id: rcs-to-cvs,v 1.4 1994/09/21 07:23:16 berliner 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
+
+umask 22
+
+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 b/gnu/usr.bin/cvs/contrib/rcs2log
new file mode 100644
index 000000000000..d7900025b851
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/rcs2log
@@ -0,0 +1,326 @@
+#!/bin/sh
+
+# RCS to ChangeLog generator
+
+# Generate a change log prefix from RCS/* and the existing 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>
+
+# OrigId: rcs2log,v 1.9 1993/01/15 05:33:29 eggert Exp
+
+# Copyright 1992, 1993 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.
+
+
+# Parse options.
+
+# defaults
+indent=8 # indent of log line
+length=79 # suggested max width of log line
+tabwidth=8 # width of horizontal tab
+
+while :
+do
+ case $1 in
+ -i) indent=${2?};;
+ -l) length=${2?};;
+ -t) tabwidth=${2?};;
+ -*) echo >&2 "$0: usage: $0 [-i indent] [-l length] [-t tabwidth] [file ...]"
+ exit 1;;
+ *) break
+ esac
+ shift; shift
+done
+
+
+# Log into $rlogout the revisions checked in since the first ChangeLog entry.
+
+date=1970
+if test -s ChangeLog
+then
+ # Add 1 to seconds to avoid duplicating most recent log.
+ # It's a good thing `rlog' doesn't mind a time ending in `:60'.
+ e='
+ /^... ... [ 0-9][0-9] [ 0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9]+ /{
+ printf "%s%02d %s\n", substr($0,1,17), substr($0,18,2)+1, $5
+ exit
+ }
+ '
+ d=`awk "$e" <ChangeLog` || exit
+ case $d in
+ ?*) date=$d
+ esac
+fi
+datearg="-d>$date"
+
+rlogout=/tmp/chg$$
+trap exit 1 2 13 15
+trap 'rm -f $rlogout; exit 1' 0
+
+case $# in
+0) set RCS/*
+esac
+
+rlog "$datearg" "$@" >$rlogout || 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=
+authors=`
+ sed -n 's|^date: *[0-9]*/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]; *author: *\([^; ]*\).*|\1|p' <$rlogout |
+ sort -u
+`
+case $authors in
+?*)
+ initialize_author=
+ for author in $authors
+ do
+ initialize_author="$initialize_author
+ author[\"$author\"] = 1
+ "
+ done
+
+ awkscript='
+ BEGIN {
+ alphabet = "abcdefghijklmnopqrstuvwxyz"
+ ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ '"$initialize_author"'
+ }
+ {
+ if (author[$1]) {
+ fullname = $5
+ 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)
+ }
+ printf "fullname[\"%s\"] = \"%s\"\n", $1, fullname
+ author[$1] = 0
+ }
+ }
+ '
+
+ initialize_fullname=`
+ (cat /etc/passwd; ypmatch $authors passwd) 2>/dev/null |
+ awk -F: "$awkscript"
+ `
+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, "\r")) 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, "\r")) != 0) {
+ printf "%s%s\n", sep, substr(Log, 1, i-1)
+ sep = indent_string
+ Log = substr(Log, i+1)
+ }
+}'
+
+hostname=`(
+ hostname || cat /etc/whoami || uuname -l || uname -n
+) 2>/dev/null` || {
+ echo >&2 "$0: cannot deduce hostname"
+ exit 1
+}
+
+
+# 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 '
+ /^Working file:/ { filename = $3 }
+ /^date: /, /^(-----------*|===========*)$/ {
+ if ($0 ~ /^branches: /) { next }
+ if ($0 ~ /^date: [0-9][ /0-9:]*;/) {
+ time = substr($3, 1, length($3)-1)
+ author = substr($5, 1, length($5)-1)
+ printf "%s %s %s %s \r", filename, $2, time, author
+ next
+ }
+ if ($0 ~ /^(-----------*|===========*)$/) { print ""; next }
+ printf "%s\r", $0
+ }
+' |
+
+# 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 {
+
+ # Initialize the fullname associative array.
+ '"$initialize_fullname"'
+
+ # 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"
+
+ 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
+ }
+
+ {
+ newlog = substr($0, 1 + index($0, "\r"))
+
+ # 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 ~ /^{[^ }]*}[ ]/) {
+ i = index(newlog, "}")
+ newclumpname = substr(newlog, 1, i)
+ while (substr(newlog, i+1) ~ /^[ ]/) 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)" if the fullname is known;
+ # print "date author" otherwise.
+ # Get the fullname from the associative array.
+ # The email address is just author@thishostname.
+ printf "%s %s %2d %s %d ", w[days_since_Sunday_before_epoch%7], m[month-1], day, $3, year
+ if (fullname[author])
+ printf "%s (%s@%s)\n\n", fullname[author], author, "'"$hostname"'"
+ else
+ printf "%s\n\n", author
+ }
+ 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 $rlogout
diff --git a/gnu/usr.bin/cvs/contrib/rcs2sccs b/gnu/usr.bin/cvs/contrib/rcs2sccs
new file mode 100644
index 000000000000..054ac6c1eca9
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/rcs2sccs
@@ -0,0 +1,143 @@
+#!/bin/sh
+#
+#
+# OrigId: rcs2sccs,v 1.12 90/10/04 20:52:23 kenc Exp Locker: kenc
+# $Id: rcs2sccs,v 1.1 1993/12/06 06:37:14 berliner Exp $
+
+############################################################
+# Error checking
+#
+if [ ! -d SCCS ] ; then
+ mkdir SCCS
+fi
+
+logfile=/tmp/rcs2sccs_$$_log
+rm -f $logfile
+tmpfile=/tmp/rcs2sccs_$$_tmp
+rm -f $tmpfile
+emptyfile=/tmp/rcs2sccs_$$_empty
+echo -n "" > $emptyfile
+initialfile=/tmp/rcs2sccs_$$_init
+echo "Initial revision" > $initialfile
+sedfile=/tmp/rcs2sccs_$$_sed
+rm -f $sedfile
+revfile=/tmp/rcs2sccs_$$_rev
+rm -f $revfile
+commentfile=/tmp/rcs2sccs_$$_comment
+rm -f $commentfile
+
+# create the sed script
+cat > $sedfile << EOF
+s,;Id;,%Z%%M% %I% %E%,g
+s,;SunId;,%Z%%M% %I% %E%,g
+s,;RCSfile;,%M%,g
+s,;Revision;,%I%,g
+s,;Date;,%E%,g
+s,;Id:.*;,%Z%%M% %I% %E%,g
+s,;SunId:.*;,%Z%%M% %I% %E%,g
+s,;RCSfile:.*;,%M%,g
+s,;Revision:.*;,%I%,g
+s,;Date:.*;,%E%,g
+EOF
+sed -e 's/;/\\$/g' $sedfile > $tmpfile
+cp $tmpfile $sedfile
+############################################################
+# Loop over every RCS file in RCS dir
+#
+for vfile in *,v; do
+ # get rid of the ",v" at the end of the name
+ file=`echo $vfile | sed -e 's/,v$//'`
+
+ # work on each rev of that file in ascending order
+ firsttime=1
+ rlog $file | grep "^revision [0-9][0-9]*\." | awk '{print $2}' | sed -e 's/\./ /g' | sort -n -u +0 +1 +2 +3 +4 +5 +6 +7 +8 | sed -e 's/ /./g' > $revfile
+ for rev in `cat $revfile`; do
+ if [ $? != 0 ]; then
+ echo ERROR - revision
+ exit
+ fi
+ # get file into current dir and get stats
+ date=`rlog -r$rev $file | grep "^date: " | awk '{print $2; exit}' | sed -e 's/^19//'`
+ time=`rlog -r$rev $file | grep "^date: " | awk '{print $3; exit}' | sed -e 's/;//'`
+ author=`rlog -r$rev $file | grep "^date: " | awk '{print $5; exit}' | sed -e 's/;//'`
+ date="$date $time"
+ echo ""
+ rlog -r$rev $file | sed -e '/^branches: /d' -e '1,/^date: /d' -e '/^===========/d' -e 's/$/\\/' | awk '{if ((total += length($0) + 1) < 510) print $0}' > $commentfile
+ echo "==> file $file, rev=$rev, date=$date, author=$author"
+ rm -f $file
+ co -r$rev $file >> $logfile 2>&1
+ if [ $? != 0 ]; then
+ echo ERROR - co
+ exit
+ fi
+ echo checked out of RCS
+
+ # add SCCS keywords in place of RCS keywords
+ sed -f $sedfile $file > $tmpfile
+ if [ $? != 0 ]; then
+ echo ERROR - sed
+ exit
+ fi
+ echo performed keyword substitutions
+ rm -f $file
+ cp $tmpfile $file
+
+ # check file into SCCS
+ if [ "$firsttime" = "1" ]; then
+ firsttime=0
+ echo about to do sccs admin
+ echo sccs admin -n -i$file $file < $commentfile
+ sccs admin -n -i$file $file < $commentfile >> $logfile 2>&1
+ if [ $? != 0 ]; then
+ echo ERROR - sccs admin
+ exit
+ fi
+ echo initial rev checked into SCCS
+ else
+ case $rev in
+ *.*.*.*)
+ brev=`echo $rev | sed -e 's/\.[0-9]*$//'`
+ sccs admin -fb $file 2>>$logfile
+ echo sccs get -e -p -r$brev $file
+ sccs get -e -p -r$brev $file >/dev/null 2>>$logfile
+ ;;
+ *)
+ echo sccs get -e -p $file
+ sccs get -e -p $file >/dev/null 2>> $logfile
+ ;;
+ esac
+ if [ $? != 0 ]; then
+ echo ERROR - sccs get
+ exit
+ fi
+ sccs delta $file < $commentfile >> $logfile 2>&1
+ if [ $? != 0 ]; then
+ echo ERROR - sccs delta -r$rev $file
+ exit
+ fi
+ echo checked into SCCS
+ fi
+ sed -e "s;^d D $rev ../../.. ..:..:.. [^ ][^ ]*;d D $rev $date $author;" SCCS/s.$file > $tmpfile
+ rm -f SCCS/s.$file
+ cp $tmpfile SCCS/s.$file
+ chmod 444 SCCS/s.$file
+ sccs admin -z $file
+ if [ $? != 0 ]; then
+ echo ERROR - sccs admin -z
+ exit
+ fi
+ done
+ rm -f $file
+done
+
+
+############################################################
+# Clean up
+#
+echo cleaning up...
+rm -f $tmpfile $emptyfile $initialfile $sedfile $commentfile
+echo ===================================================
+echo " Conversion Completed Successfully"
+echo ===================================================
+
+rm -f *,v
diff --git a/gnu/usr.bin/cvs/contrib/sccs2rcs b/gnu/usr.bin/cvs/contrib/sccs2rcs
new file mode 100644
index 000000000000..654024bf3fc3
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/sccs2rcs
@@ -0,0 +1,277 @@
+#!/bin/csh -f
+#
+# Sccs2rcs is a script to convert an existing SCCS
+# history into an RCS history without losing any of
+# the information contained therein.
+# It has been tested under the following OS's:
+# SunOS 3.5, 4.0.3, 4.1
+# Ultrix-32 2.0, 3.1
+#
+# Things to note:
+# + It will NOT delete or alter your ./SCCS history under any circumstances.
+#
+# + Run in a directory where ./SCCS exists and where you can
+# create ./RCS
+#
+# + /usr/local/bin is put in front of the default path.
+# (SCCS under Ultrix is set-uid sccs, bad bad bad, so
+# /usr/local/bin/sccs here fixes that)
+#
+# + Date, time, author, comments, branches, are all preserved.
+#
+# + If a command fails somewhere in the middle, it bombs with
+# a message -- remove what it's done so far and try again.
+# "rm -rf RCS; sccs unedit `sccs tell`; sccs clean"
+# There is no recovery and exit is far from graceful.
+# If a particular module is hanging you up, consider
+# doing it separately; move it from the current area so that
+# the next run will have a better chance or working.
+# Also (for the brave only) you might consider hacking
+# the s-file for simpler problems: I've successfully changed
+# the date of a delta to be in sync, then run "sccs admin -z"
+# on the thing.
+#
+# + After everything finishes, ./SCCS will be moved to ./old-SCCS.
+#
+# This file may be copied, processed, hacked, mutilated, and
+# even destroyed as long as you don't tell anyone you wrote it.
+#
+# Ken Cox
+# Viewlogic Systems, Inc.
+# kenstir@viewlogic.com
+# ...!harvard!cg-atla!viewlog!kenstir
+#
+# Various hacks made by Brian Berliner before inclusion in CVS contrib area.
+#
+# $Id: sccs2rcs,v 1.1 1992/04/10 03:04:26 berliner Exp $
+
+
+#we'll assume the user set up the path correctly
+# for the Pmax, /usr/ucb/sccs is suid sccs, what a pain
+# /usr/local/bin/sccs should override /usr/ucb/sccs there
+set path = (/usr/local/bin $path)
+
+
+############################################################
+# Error checking
+#
+if (! -w .) then
+ echo "Error: ./ not writeable by you."
+ exit 1
+endif
+if (! -d SCCS) then
+ echo "Error: ./SCCS directory not found."
+ exit 1
+endif
+set edits = (`sccs tell`)
+if ($#edits) then
+ echo "Error: $#edits file(s) out for edit...clean up before converting."
+ exit 1
+endif
+if (-d RCS) then
+ echo "Warning: RCS directory exists"
+ if (`ls -a RCS | wc -l` > 2) then
+ echo "Error: RCS directory not empty
+ exit 1
+ endif
+else
+ mkdir RCS
+endif
+
+sccs clean
+
+set logfile = /tmp/sccs2rcs_$$_log
+rm -f $logfile
+set tmpfile = /tmp/sccs2rcs_$$_tmp
+rm -f $tmpfile
+set emptyfile = /tmp/sccs2rcs_$$_empty
+echo -n "" > $emptyfile
+set initialfile = /tmp/sccs2rcs_$$_init
+echo "Initial revision" > $initialfile
+set sedfile = /tmp/sccs2rcs_$$_sed
+rm -f $sedfile
+set revfile = /tmp/sccs2rcs_$$_rev
+rm -f $revfile
+
+# the quotes surround the dollar signs to fool RCS when I check in this script
+set sccs_keywords = (\
+ '%W%[ ]*%G%'\
+ '%W%[ ]*%E%'\
+ '%W%'\
+ '%Z%%M%[ ]*%I%[ ]*%G%'\
+ '%Z%%M%[ ]*%I%[ ]*%E%'\
+ '%M%[ ]*%I%[ ]*%G%'\
+ '%M%[ ]*%I%[ ]*%E%'\
+ '%M%'\
+ '%I%'\
+ '%G%'\
+ '%E%'\
+ '%U%')
+set rcs_keywords = (\
+ '$'Id'$'\
+ '$'Id'$'\
+ '$'Id'$'\
+ '$'SunId'$'\
+ '$'SunId'$'\
+ '$'Id'$'\
+ '$'Id'$'\
+ '$'RCSfile'$'\
+ '$'Revision'$'\
+ '$'Date'$'\
+ '$'Date'$'\
+ '')
+
+
+############################################################
+# Get some answers from user
+#
+echo ""
+echo "Do you want to be prompted for a description of each"
+echo "file as it is checked in to RCS initially?"
+echo -n "(y=prompt for description, n=null description) [y] ?"
+set ans = $<
+if ((_$ans == _) || (_$ans == _y) || (_$ans == _Y)) then
+ set nodesc = 0
+else
+ set nodesc = 1
+endif
+echo ""
+echo "The default keyword substitutions are as follows and are"
+echo "applied in the order specified:"
+set i = 1
+while ($i <= $#sccs_keywords)
+# echo ' '\"$sccs_keywords[$i]\"' ==> '\"$rcs_keywords[$i]\"
+ echo " $sccs_keywords[$i] ==> $rcs_keywords[$i]"
+ @ i = $i + 1
+end
+echo ""
+echo -n "Do you want to change them [n] ?"
+set ans = $<
+if ((_$ans != _) && (_$ans != _n) && (_$ans != _N)) then
+ echo "You can't always get what you want."
+ echo "Edit this script file and change the variables:"
+ echo ' $sccs_keywords'
+ echo ' $rcs_keywords'
+else
+ echo "good idea."
+endif
+
+# create the sed script
+set i = 1
+while ($i <= $#sccs_keywords)
+ echo "s,$sccs_keywords[$i],$rcs_keywords[$i],g" >> $sedfile
+ @ i = $i + 1
+end
+
+onintr ERROR
+
+############################################################
+# Loop over every s-file in SCCS dir
+#
+foreach sfile (SCCS/s.*)
+ # get rid of the "s." at the beginning of the name
+ set file = `echo $sfile:t | sed -e "s/^..//"`
+
+ # work on each rev of that file in ascending order
+ set firsttime = 1
+ sccs prs $file | grep "^D " | awk '{print $2}' | sed -e 's/\./ /g' | sort -n -u +0 +1 +2 +3 +4 +5 +6 +7 +8 | sed -e 's/ /./g' > $revfile
+ foreach rev (`cat $revfile`)
+ if ($status != 0) goto ERROR
+
+ # get file into current dir and get stats
+ set date = `sccs prs -r$rev $file | grep "^D " | awk '{printf("19%s %s", $3, $4); exit}'`
+ set author = `sccs prs -r$rev $file | grep "^D " | awk '{print $5; exit}'`
+ echo ""
+ echo "==> file $file, rev=$rev, date=$date, author=$author"
+ sccs edit -r$rev $file >>& $logfile
+ if ($status != 0) goto ERROR
+ echo checked out of SCCS
+
+ # add RCS keywords in place of SCCS keywords
+ sed -f $sedfile $file > $tmpfile
+ if ($status != 0) goto ERROR
+ echo performed keyword substitutions
+ cp $tmpfile $file
+
+ # check file into RCS
+ if ($firsttime) then
+ set firsttime = 0
+ if ($nodesc) then
+ echo about to do ci
+ echo ci -f -r$rev -d"$date" -w$author -t$emptyfile $file
+ ci -f -r$rev -d"$date" -w$author -t$emptyfile $file < $initialfile >>& $logfile
+ if ($status != 0) goto ERROR
+ echo initial rev checked into RCS without description
+ else
+ echo ""
+ echo Enter a brief description of the file $file \(end w/ Ctrl-D\):
+ cat > $tmpfile
+ ci -f -r$rev -d"$date" -w$author -t$tmpfile $file < $initialfile >>& $logfile
+ if ($status != 0) goto ERROR
+ echo initial rev checked into RCS
+ endif
+ else
+ # get RCS lock
+ set lckrev = `echo $rev | sed -e 's/\.[0-9]*$//'`
+ if ("$lckrev" =~ [0-9]*.*) then
+ # need to lock the brach -- it is OK if the lock fails
+ rcs -l$lckrev $file >>& $logfile
+ else
+ # need to lock the trunk -- must succeed
+ rcs -l $file >>& $logfile
+ if ($status != 0) goto ERROR
+ endif
+ echo got lock
+ sccs prs -r$rev $file | grep "." > $tmpfile
+ # it's OK if grep fails here and gives status == 1
+ # put the delta message in $tmpfile
+ ed $tmpfile >>& $logfile <<EOF
+/COMMENTS
+1,.d
+w
+q
+EOF
+ ci -f -r$rev -d"$date" -w$author $file < $tmpfile >>& $logfile
+ if ($status != 0) goto ERROR
+ echo checked into RCS
+ endif
+ sccs unedit $file >>& $logfile
+ if ($status != 0) goto ERROR
+ end
+ rm -f $file
+end
+
+
+############################################################
+# Clean up
+#
+echo cleaning up...
+mv SCCS old-SCCS
+rm -f $tmpfile $emptyfile $initialfile $sedfile
+echo ===================================================
+echo " Conversion Completed Successfully"
+echo ""
+echo " SCCS history now in old-SCCS/"
+echo ===================================================
+set exitval = 0
+goto cleanup
+
+ERROR:
+foreach f (`sccs tell`)
+ sccs unedit $f
+end
+echo ""
+echo ""
+echo Danger\! Danger\!
+echo Some command exited with a non-zero exit status.
+echo Log file exists in $logfile.
+echo ""
+echo Incomplete history in ./RCS -- remove it
+echo Original unchanged history in ./SCCS
+set exitval = 1
+
+cleanup:
+# leave log file
+rm -f $tmpfile $emptyfile $initialfile $sedfile $revfile
+
+exit $exitval