diff options
author | cvs2svn <cvs2svn@FreeBSD.org> | 1996-01-01 11:01:15 +0000 |
---|---|---|
committer | cvs2svn <cvs2svn@FreeBSD.org> | 1996-01-01 11:01:15 +0000 |
commit | a3ab491d642b34f2d3efbc0562abc8e79b38ce09 (patch) | |
tree | 959df5086a97d16c04b83842650d6ee1f3de4522 /gnu/usr.bin/cvs/contrib | |
parent | 4e2d078f4fc7fe46c0e3b0f1256c92e971891c67 (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/clmerge | 156 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/contrib/cvscheck | 84 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/contrib/descend | 116 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/contrib/dirfns | 481 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/contrib/easy-import.perl | 388 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/contrib/pcl-cvs/cookie.el | 884 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll-debug.el | 298 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll.el | 386 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/contrib/pcl-cvs/elib-node.el | 89 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/contrib/rcs-to-cvs | 184 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/contrib/rcs2log | 326 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/contrib/rcs2sccs | 143 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/contrib/sccs2rcs | 277 |
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 |