Updated CVS

This commit is contained in:
Jordan K. Hubbard 1993-06-18 05:46:17 +00:00
commit db4427d334
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/cvs/dist/; revision=12
svn path=/vendor/cvs/1.3/; revision=14; tag=vendor/misc-GNU/cvs/1.3
110 changed files with 45398 additions and 0 deletions

3
gnu/usr.bin/cvs/Makefile Normal file
View File

@ -0,0 +1,3 @@
SUBDIR = lib cvs mkmodules
.include <bsd.subdir.mk>

View File

@ -0,0 +1,68 @@
@(#)README 1.8 92/04/10
This "contrib" directory is a place holder for code/scripts sent to
me by contributors around the world. This READM file will be kept
up-to-date from release to release. BUT, I must point out that these
contributions are really, REALLY UNSSUPPORTED. In fact, I probably
don't even know what they do. Nor do I guarantee to have tried them,
or ported them to work with this CVS distribution. If you have questions,
you might contact the author, but you should not necessarily expect
a reply. USE AT YOUR OWN RISK -- and all that stuff.
Contents of this directory:
README This file.
log.pl A perl script suitable for including in your
$CVSROOT/CVSROOT/loginfo file for logging commit
changes. Includes the RCS revision of the change
as part of the log.
Contributed by Kevin Samborn <samborn@sunrise.com>.
pcl-cvs A directory that contains GNU Emacs lisp code which
implements a CVS-mode for emacs.
Contributed by Per Cederqvist <ceder@lysator.liu.se>.
commit_prep.pl A perl script, to be combined with log_accum.pl, to
log_accum.pl provide for a way to combine the individual log
messages of a multi-directory "commit" into a
single log message, and mail the result somewhere.
Also does other checks for $Id and that you are
committing the correct revision of the file.
Read the comments carefully.
Contributed by David Hampton <hampton@cisco.com>.
mfpipe.pl Another perl script for logging. Allows you to
pipe the log message to a file and/or send mail
to some alias.
Contributed by John Clyne <clyne@niwot.scd.ucar.edu>.
rcs-to-cvs Script to import sources that may have been under
RCS control already.
Contributed by Per Cederqvist <ceder@lysator.liu.se>.
cvscheck Identifies files added, changed, or removed in a
cvscheck.man checked out CVS tree; also notices unknown files.
Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
cvshelp.man An introductory manual page written by Lowell Skoog
<fluke!lowell@uunet.uu.net>. It is most likely
out-of-date relative to CVS 1.3, but still may be
useful.
dirfns A shar file which contains some code that might
help your system support opendir/readdir/closedir,
if it does not already.
Copied from the C-News distribution.
rcslock.pl A perl script that can be added to your commitinfo
file that tries to determine if your RCS file is
currently locked by someone else, as might be the
case for a binary file.
Contributed by John Rouillard <rouilj@cs.umb.edu>.
cvs_acls.pl A perl script that implements Access Control Lists
by using the "commitinfo" hook provided with the
"cvs commit" command.
Contributed by David G. Grubbs <dgg@ksr.com>.
descend A shell script that can be used to recursively
descend.man descend through a directory. In CVS 1.2, this was
very useful, since many of the commands were not
recursive. In CVS 1.3 (and later), however, most of
the commands are recursive. However, this may still
come in handy.
Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
cln_hist.pl A perl script to compress your
$CVSROOT/CVSROOT/history file, as it can grow quite
large after extended use.
Contributed by David G. Grubbs <dgg@ksr.com>

View File

@ -0,0 +1,91 @@
#!/usr/bin/perl -- # -*-Perl-*-
#
# cln_hist.pl,v 1.1 1992/04/10 03:04:15 berliner Exp
# Contributed by David G. Grubbs <dgg@ksr.com>
#
# Clean up the history file. 10 Record types: MAR OFT WUCG
#
# WUCG records are thrown out.
# MAR records are retained.
# T records: retain only last tag with same combined tag/module.
#
# Two passes: Walk through the first time and remember the
# 1. Last Tag record with same "tag" and "module" names.
# 2. Last O record with unique user/module/directory, unless followed
# by a matching F record.
#
$r = $ENV{"CVSROOT"};
$c = "$r/CVSROOT";
$h = "$c/history";
eval "print STDERR \$die='Unknown parameter $1\n' if !defined \$$1; \$$1=\$';"
while ($ARGV[0] =~ /^(\w+)=/ && shift(@ARGV));
exit 255 if $die; # process any variable=value switches
%tags = ();
%outs = ();
#
# Move history file to safe place and re-initialize a new one.
#
rename($h, "$h.bak");
open(XX, ">$h");
close(XX);
#
# Pass1 -- remember last tag and checkout.
#
open(HIST, "$h.bak");
while (<HIST>) {
next if /^[MARWUCG]/;
# Save whole line keyed by tag|module
if (/^T/) {
@tmp = split(/\|/, $_);
$tags{$tmp[4] . '|' . $tmp[5]} = $_;
}
# Save whole line
if (/^[OF]/) {
@tmp = split(/\|/, $_);
$outs{$tmp[1] . '|' . $tmp[2] . '|' . $tmp[5]} = $_;
}
}
#
# Pass2 -- print out what we want to save.
#
open(SAVE, ">$h.work");
open(HIST, "$h.bak");
while (<HIST>) {
next if /^[FWUCG]/;
# If whole line matches saved (i.e. "last") one, print it.
if (/^T/) {
@tmp = split(/\|/, $_);
next if $tags{$tmp[4] . '|' . $tmp[5]} ne $_;
}
# Save whole line
if (/^O/) {
@tmp = split(/\|/, $_);
next if $outs{$tmp[1] . '|' . $tmp[2] . '|' . $tmp[5]} ne $_;
}
print SAVE $_;
}
#
# Put back the saved stuff
#
system "cat $h >> $h.work";
if (-s $h) {
rename ($h, "$h.interim");
print "history.interim has non-zero size.\n";
} else {
unlink($h);
}
rename ("$h.work", $h);
exit(0);

View File

@ -0,0 +1,168 @@
#!/usr/local/bin/perl -w
#
#
# Perl filter to handle pre-commit checking of files. This program
# records the last directory where commits will be taking place for
# use by the log_accumulate script. For new file, it forcing the
# existence of a RCS "Id" keyword in the first ten lines of the file.
# For existing files, it checks version number in the "Id" line to
# prevent losing changes because an old version of a file was copied
# into the direcory.
#
# Possible future enhancements:
#
#
# Check for cruft left by unresolved conflicts. Search for
# "^<<<<<<<$", "^-------$", and "^>>>>>>>$".
#
# Look for a copyright and automagically update it to the
# current year.
#
# Contributed by David Hampton <hampton@cisco.com>
#
############################################################
#
# Configurable options
#
############################################################
#
# Check each file (except dot files) for an RCS "Id" keyword.
#
$check_id = 1;
#
# Record the directory for later use by the log_accumulate stript.
#
$record_directory = 1;
############################################################
#
# Constants
#
############################################################
$LAST_FILE = "/tmp/#cvs.lastdir";
$ENTRIES = "CVS/Entries";
$NoId = "
%s - Does not contain a line with the keyword \"Id:\".
Please see the template files for an example.\n";
# Protect string from substitution by RCS.
$NoName = "
%s - The ID line should contain only \"\$\I\d\:\ \$\" for a newly created file.\n";
$BadName = "
%s - The file name '%s' in the ID line does not match
the actual filename.\n";
$BadVersion = "
%s - How dare you!! You replaced your copy of the file '%s',
which was based upon version %s, with an %s version based
upon %s. Please move your '%s' out of the way, perform an
update to get the current version, and them merge your changes
into that file.\n";
############################################################
#
# Subroutines
#
############################################################
sub write_line {
local($filename, $line) = @_;
open(FILE, ">$filename") || die("Cannot open $filename, stopped");
print(FILE $line, "\n");
close(FILE);
}
sub check_version {
local($i, $id, $rname, $version);
local($filename, $cvsversion) = @_;
open(FILE, $filename) || die("Cannot open $filename, stopped");
for ($i = 1; $i < 10; $i++) {
$pos = -1;
last if eof(FILE);
$line = <FILE>;
$pos = index($line, "Id: ");
last if ($pos >= 0);
}
if ($pos == -1) {
printf($NoId, $filename);
return(1);
}
($id, $rname, $version) = split(' ', substr($line, $pos));
if ($cvsversion{$filename} == 0) {
if ($rname ne "\$") {
printf($NoName, $filename);
return(1);
}
return(0);
}
if ($rname ne "$filename,v") {
printf($BadName, $filename, substr($rname, 0, length($rname)-2));
return(1);
}
if ($cvsversion{$filename} < $version) {
printf($BadVersion, $filename, $filename, $cvsversion{$filename},
"newer", $version, $filename);
return(1);
}
if ($cvsversion{$filename} > $version) {
printf($BadVersion, $filename, $filename, $cvsversion{$filename},
"older", $version, $filename);
return(1);
}
return(0);
}
#############################################################
#
# Main Body
#
############################################################
$id = getpgrp();
#print("ARGV - ", join(":", @ARGV), "\n");
#print("id - ", id, "\n");
#
# Suck in the Entries file
#
open(ENTRIES, $ENTRIES) || die("Cannot open $ENTRIES.\n");
while (<ENTRIES>) {
local($filename, $version) = split('/', substr($_, 1));
$cvsversion{$filename} = $version;
}
#
# Now check each file name passed in, except for dot files. Dot files
# are considered to be administrative files by this script.
#
if ($check_id != 0) {
$failed = 0;
$directory = $ARGV[0];
shift @ARGV;
foreach $arg (@ARGV) {
next if (index($arg, ".") == 0);
$failed += &check_version($arg);
}
if ($failed) {
print "\n";
exit(1);
}
}
#
# Record this directory as the last one checked. This will be used
# by the log_accumulate script to determine when it is processing
# the final directory of a multi-directory commit.
#
if ($record_directory != 0) {
&write_line("$LAST_FILE.$id", $directory);
}
exit(0);

View File

@ -0,0 +1,142 @@
#!/usr/bin/perl -- # -*-Perl-*-
#
# cvs_acls.pl,v 1.2 1992/04/11 16:01:24 berliner Exp
#
# Access control lists for CVS. dgg@ksr.com (David G. Grubbs)
#
# CVS "commitinfo" for matching repository names, running the program it finds
# on the same line. More information is available in the CVS man pages.
#
# ==== INSTALLATION:
#
# To use this program as I intended, do the following four things:
#
# 0. Install PERL. :-)
#
# 1. Put one line, as the *only* non-comment line, in your commitinfo file:
#
# DEFAULT /usr/local/bin/cvs_acls
#
# 2. Install this file as /usr/local/bin/cvs_acls and make it executable.
#
# 3. Create a file named $CVSROOT/CVSROOT/avail.
#
# ==== FORMAT OF THE avail FILE:
#
# The avail file determines whether you may commit files. It contains lines
# read from top to bottom, keeping track of a single "bit". The "bit"
# defaults to "on". It can be turned "off" by "unavail" lines and "on" by
# "avail" lines. ==> Last one counts.
#
# Any line not beginning with "avail" or "unavail" is ignored.
#
# Lines beginning with "avail" or "unavail" are assumed to be '|'-separated
# triples: (All spaces and tabs are ignored in a line.)
#
# {avail.*,unavail.*} [| user,user,... [| repos,repos,...]]
#
# 1. String starting with "avail" or "unavail".
# 2. Optional, comma-separated list of usernames.
# 3. Optional, comma-separated list of repository pathnames.
# These are pathnames relative to $CVSROOT. They can be directories or
# filenames. A directory name allows access to all files and
# directories below it.
#
# Example: (Text from the ';;' rightward may not appear in the file.)
#
# unavail ;; Make whole repository unavailable.
# avail|dgg ;; Except for user "dgg".
# avail|fred, john|bin/ls ;; Except when "fred" or "john" commit to
# ;; the module whose repository is "bin/ls"
#
# PROGRAM LOGIC:
#
# CVS passes to @ARGV an absolute directory pathname (the repository
# appended to your $CVSROOT variable), followed by a list of filenames
# within that directory.
#
# We walk through the avail file looking for a line that matches both
# the username and repository.
#
# A username match is simply the user's name appearing in the second
# column of the avail line in a space-or-comma separate list.
#
# A repository match is either:
# - One element of the third column matches $ARGV[0], or some
# parent directory of $ARGV[0].
# - Otherwise *all* file arguments ($ARGV[1..$#ARGV]) must be
# in the file list in one avail line.
# - In other words, using directory names in the third column of
# the avail file allows committing of any file (or group of
# files in a single commit) in the tree below that directory.
# - If individual file names are used in the third column of
# the avail file, then files must be committed individually or
# all files specified in a single commit must all appear in
# third column of a single avail line.
#
$debug = 0;
$cvsroot = $ENV{'CVSROOT'};
$availfile = $cvsroot . "/CVSROOT/avail";
$myname = $ENV{"USER"} if !($myname = $ENV{"LOGNAME"});
eval "print STDERR \$die='Unknown parameter $1\n' if !defined \$$1; \$$1=\$';"
while ($ARGV[0] =~ /^(\w+)=/ && shift(@ARGV));
exit 255 if $die; # process any variable=value switches
die "Must set CVSROOT\n" if !$cvsroot;
($repos = shift) =~ s:^$cvsroot/::;
grep($_ = $repos . '/' . $_, @ARGV);
print "$$ Repos: $repos\n","$$ ==== ",join("\n$$ ==== ",@ARGV),"\n" if $debug;
$exit_val = 0; # Good Exit value
$universal_off = 0;
open (AVAIL, $availfile) || exit(0); # It is ok for avail file not to exist
while (<AVAIL>) {
chop;
next if /^\s*\#/;
next if /^\s*$/;
($flagstr, $u, $m) = split(/[\s,]*\|[\s,]*/, $_);
# Skip anything not starting with "avail" or "unavail" and complain.
(print "Bad avail line: $_\n"), next
if ($flagstr !~ /^avail/ && $flagstr !~ /^unavail/);
# Set which bit we are playing with. ('0' is OK == Available).
$flag = (($& eq "avail") ? 0 : 1);
# If we find a "universal off" flag (i.e. a simple "unavail") remember it
$universal_off = 1 if ($flag && !$u && !$m);
# $myname considered "in user list" if actually in list or is NULL
$in_user = (!$u || grep ($_ eq $myname, split(/[\s,]+/,$u)));
print "$$ \$myname($myname) in user list: $_\n" if $debug && $in_user;
# Module matches if it is a NULL module list in the avail line. If module
# list is not null, we check every argument combination.
if (!($in_repo = !$m)) {
@tmp = split(/[\s,]+/,$m);
for $j (@tmp) {
# If the repos from avail is a parent(or equal) dir of $repos, OK
$in_repo = 1, last if ($repos eq $j || $repos =~ /^$j\//);
}
if (!$in_repo) {
$in_repo = 1;
for $j (@ARGV) {
last if !($in_repo = grep ($_ eq $j, @tmp));
}
}
}
print "$$ \$repos($repos) in repository list: $_\n" if $debug && $in_repo;
$exit_val = $flag if ($in_user && $in_repo);
print "$$ ==== \$exit_val = $exit_val\n$$ ==== \$flag = $flag\n" if $debug;
}
close(AVAIL);
print "$$ ==== \$exit_val = $exit_val\n" if $debug;
print "**** Access denied: Insufficient Karma ($myname|$repos)\n" if $exit_val;
print "**** Access allowed: Personal Karma exceeds Environmental Karma.\n"
if $universal_off && !$exit_val;
exit($exit_val);

View File

@ -0,0 +1,84 @@
#! /bin/sh
# cvscheck,v 1.2 1992/04/10 03:04:19 berliner Exp
#
# cvscheck - identify files added, changed, or removed
# in CVS working directory
#
# Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
#
# This program should be run in a working directory that has been
# checked out using CVS. It identifies files that have been added,
# changed, or removed in the working directory, but not "cvs
# committed". It also determines whether the files have been "cvs
# added" or "cvs removed". For directories, it is only practical to
# determine whether they have been added.
name=cvscheck
changes=0
# If we can't run CVS commands in this directory
cvs status . > /dev/null 2>&1
if [ $? != 0 ] ; then
# Bail out
echo "$name: there is no version here; bailing out" 1>&2
exit 1
fi
# Identify files added to working directory
for file in .* * ; do
# Skip '.' and '..'
if [ $file = '.' -o $file = '..' ] ; then
continue
fi
# If a regular file
if [ -f $file ] ; then
if cvs status $file | grep -s '^From:[ ]*New file' ; then
echo "file added: $file - not CVS committed"
changes=`expr $changes + 1`
elif cvs status $file | grep -s '^From:[ ]*no entry for' ; then
echo "file added: $file - not CVS added, not CVS committed"
changes=`expr $changes + 1`
fi
# Else if a directory
elif [ -d $file -a $file != CVS.adm ] ; then
# Move into it
cd $file
# If CVS commands don't work inside
cvs status . > /dev/null 2>&1
if [ $? != 0 ] ; then
echo "directory added: $file - not CVS added"
changes=`expr $changes + 1`
fi
# Move back up
cd ..
fi
done
# Identify changed files
changedfiles=`cvs diff | egrep '^diff' | awk '{print $3}'`
for file in $changedfiles ; do
echo "file changed: $file - not CVS committed"
changes=`expr $changes + 1`
done
# Identify files removed from working directory
removedfiles=`cvs status | egrep '^File:[ ]*no file' | awk '{print $4}'`
# Determine whether each file has been cvs removed
for file in $removedfiles ; do
if cvs status $file | grep -s '^From:[ ]*-' ; then
echo "file removed: $file - not CVS committed"
else
echo "file removed: $file - not CVS removed, not CVS committed"
fi
changes=`expr $changes + 1`
done
exit $changes

View File

@ -0,0 +1,53 @@
.\" cvscheck.man,v 1.1 1992/04/10 03:04:20 berliner Exp
.\" Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
.TH CVSCHECK LOCAL "4 March 1991" FLUKE
.SH NAME
cvscheck \- identify files added, changed, or removed in a CVS working
directory
.SH SYNOPSIS
.B cvscheck
.SH DESCRIPTION
This command is a housekeeping aid. It should be run in a working
directory that has been checked out using CVS. It identifies files
that have been added, changed, or removed in the working directory, but
not CVS
.BR commit ted.
It also determines whether the files have been CVS
.BR add ed
or CVS
.BR remove d.
For directories, this command determines only whether they have been
.BR add ed.
It operates in the current directory only.
.LP
This command provides information that is available using CVS
.B status
and CVS
.BR diff .
The advantage of
.B cvscheck
is that its output is very concise. It saves you the strain (and
potential error) of interpreting the output of CVS
.B status
and
.BR diff .
.LP
See
.BR cvs (local)
or
.BR cvshelp (local)
for instructions on how to add or remove a file or directory in a
CVS-controlled package.
.SH DIAGNOSTICS
The exit status is 0 if no files have been added, changed, or removed
from the current directory. Otherwise, the command returns a count of
the adds, changes, and deletes.
.SH SEE ALSO
.BR cvs (local),
.BR cvshelp (local)
.SH AUTHOR
Lowell Skoog
.br
Software Technology Group
.br
Technical Computing

View File

@ -0,0 +1,562 @@
.\" cvshelp.man,v 1.1 1992/04/10 03:04:21 berliner Exp
.\" Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
.\" Full space in nroff; half space in troff
.de SP
.if n .sp
.if t .sp .5
..
.\" Start a command example
.de XS
.SP
.in +.5i
.ft B
.nf
..
.\" End a command example
.de XE
.fi
.ft P
.in -.5i
.SP
..
.TH CVSHELP LOCAL "17 March 1991" FLUKE
.SH NAME
cvshelp \- advice on using the Concurrent Versions System
.SH DESCRIPTION
This man page is based on experience using CVS.
It is bound to change as we gain more experience.
If you come up with better advice than is found here,
contact the Software Technology
Group and we will add it to this page.
.SS "Getting Started"
Use the following steps to prepare to use CVS:
.TP
\(bu
Take a look at the CVS manual page to see what it can do for you, and
if it fits your environment (or can possibly be made to fit your
environment).
.XS
man cvs
.XE
If things look good, continue on...
.TP
\(bu
Setup the master source repository. Choose a directory with
ample disk space available for source files. This is where the RCS
`,v' files will be stored. Say you choose
.B /src/master
as the root
of your source repository. Make the
.SB CVSROOT.adm
directory in the root of the source repository:
.XS
mkdir /src/master/CVSROOT.adm
.XE
.TP
\(bu
Populate this directory with the
.I loginfo
and
.I modules
files from the
.B "/usr/doc/local/cvs"
directory. Edit these files to reflect your local source repository
environment \- they may be quite small initially, but will grow as
sources are added to your source repository. Turn these files into
RCS controlled files:
.XS
cd /src/master/CVSROOT.adm
ci \-m'Initial loginfo file' loginfo
ci \-m'Initial modules file' modules
.XE
.TP
\(bu
Run the command:
.XS
mkmodules /src/master/CVSROOT.adm
.XE
This will build the
.BR ndbm (3)
file for the modules database.
.TP
\(bu
Remember to edit the
.I modules
file manually when sources are checked
in with
.B checkin
or CVS
.BR add .
A copy of the
.I modules
file for editing can be retrieved with the command:
.XS
cvs checkout CVSROOT.adm
.XE
.TP
\(bu
Have all users of the CVS system set the
.SM CVSROOT
environment variable appropriately to reflect the placement of your
source repository. If the above example is used, the following
commands can be placed in a
.I .login
or
.I .profile
file:
.XS
setenv CVSROOT /src/master
.XE
for csh users, and
.XS
CVSROOT=/src/master; export CVSROOT
.XE
for sh users.
.SS "Placing Locally Written Sources Under CVS Control"
Say you want to place the `whizbang' sources under
CVS control. Say further that the sources have never
been under revision control before.
.TP
\(bu
Move the source hierarchy (lock, stock, and barrel)
into the master source repository:
.XS
mv ~/whizbang $CVSROOT
.XE
.TP
\(bu
Clean out unwanted object files:
.XS
cd $CVSROOT/whizbang
make clean
.XE
.TP
\(bu
Turn every file in the hierarchy into an RCS controlled file:
.XS
descend \-f 'ci \-t/dev/null \-m"Placed under CVS control" \-nV\fR\fIx\fR\fB_\fR\fIy\fR\fB *'
.XE
In this example, the initial release tag is \fBV\fIx\fB_\fIy\fR,
representing version \fIx\fR.\fIy\fR.
.LP
You can use CVS on sources that are already under RCS control.
The following example shows how.
In this example, the source package is called `skunkworks'.
.TP
\(bu
Move the source hierarchy into the master source
repository:
.XS
mv ~/skunkworks $CVSROOT
.XE
.TP
\(bu
Clean out unwanted object files:
.XS
cd $CVSROOT/skunkworks
make clean
.XE
.TP
\(bu
Clean out unwanted working files, leaving only the RCS `,v' files:
.XS
descend \-r rcsclean
.XE
Note: If any working files have been checked out and changed,
.B rcsclean
will fail. Check in the modified working files
and run the command again.
.TP
\(bu
Get rid of
.SB RCS
subdirectories. CVS does not use them.
.XS
descend \-r \-f 'mv RCS/*,v .'
descend \-r \-f 'rmdir RCS'
.XE
.TP
\(bu
Delete any unwanted files that remain in the source hierarchy. Then
make sure all files are under RCS control:
.XS
descend \-f 'ci \-t/dev/null \-m"Placed under CVS control" \-n\fR\fItag\fR\fB *'
.XE
.I tag
is the latest symbolic revision tag that you applied to your package
(if any). Note: This command will probably generate lots of error
messages (for directories and existing RCS files) that you can
ignore.
.SS "Placing a Third-Party Source Distribution Under CVS Control"
The
.B checkin
command checks third-party sources into CVS. The
difference between third-party sources and locally
written sources is that third-party sources must be checked into a
separate branch (called the
.IR "vendor branch" )
of the RCS tree. This makes it possible to merge local changes to
the sources with later releases from the vendor.
.TP
\(bu
Save the original distribution kit somewhere. For example, if the
master source repository is
.B /src/master
the distribution kit could be saved in
.BR /src/dist .
Organize the distribution directory so that each release
is clearly identifiable.
.TP
\(bu
Unpack the package in a scratch directory, for example
.BR ~/scratch .
.TP
\(bu
Create a repository for the package.
In this example, the package is called `Bugs-R-Us 4.3'.
.XS
mkdir $CVSROOT/bugs
.XE
.TP
\(bu
Check in the unpacked files:
.XS
cd ~/scratch
checkin \-m 'Bugs-R-Us 4.3 distribution' bugs VENDOR V4_3
.XE
There is nothing magic about the tag `VENDOR', which is applied to
the vendor branch. You can use whatever tag you want. `VENDOR' is a
useful convention.
.TP
\(bu
Never modify vendor files before checking them in.
Check in the files
.I exactly
as you unpacked them.
If you check in locally modified files, future vendor releases may
wipe out your local changes.
.SS "Working With CVS-Controlled Sources"
To use or edit the sources, you must check out a private copy.
For the following examples, the master files are assumed to reside in
.BR "$CVSROOT/behemoth" .
The working directory is
.BR "~/work" .
See
.BR cvs (local)
for more details on the commands mentioned below.
.TP
.I "To Check Out Working Files
Use CVS
.BR checkout :
.XS
cd ~/work
cvs checkout behemoth
.XE
There is nothing magic about the working directory. CVS will check
out sources anywhere you like. Once you have a working copy of the
sources, you can compile or edit them as desired.
.TP
.I "To Display Changes You Have Made"
Use CVS
.BR diff
to display detailed changes, equivalent to
.BR rcsdiff (local).
You can also use
.BR cvscheck (local)
to list files added, changed, and removed in
the directory, but not yet
.BR commit ted.
You must be in a directory containing working files.
.TP
.I "To Display Revision Information"
Use CVS
.BR log ,
which is equivalent to
.BR rlog (local).
You must be in a directory containing working files.
.TP
.I "To Update Working Files"
Use CVS
.BR update
in a directory containing working files.
This command brings your working files up
to date with changes checked into the
master repository since you last checked out or updated
your files.
.TP
.I "To Check In Your Changes"
Use CVS
.BR commit
in a directory containing working files.
This command checks your changes into the master repository.
You can specify files by name or use
.XS
cvs commit \-a
.XE
to
.B commit
all the files you have changed.
.TP
.I "To Add a File"
Add the file to the working directory.
Use CVS
.B add
to mark the file as added.
Use CVS
.B commit
to add the file to the master repository.
.TP
.I "To Remove a File"
Remove the file from the working directory.
Use CVS
.B remove
to mark the file as removed.
Use CVS
.B commit
to move the file from its current location in the master repository
to the CVS
.IR Attic
directory.
.TP
.I "To Add a Directory"
Add the directory to the working directory.
Use CVS
.B add
to add the directory to the master repository.
.TP
.I "To Remove a Directory"
.br
You shouldn't remove directories under CVS. You should instead remove
their contents and then prune them (using the
.B \-f
and
.B \-p
options) when you
.B checkout
or
.B update
your working files.
.TP
.I "To Tag a Release"
Use CVS
.B tag
to apply a symbolic tag to the latest revision of each file in the
master repository. For example:
.XS
cvs tag V2_1 behemoth
.XE
.TP
.I "To Retrieve an Exact Copy of a Previous Release"
During a CVS
.B checkout
or
.BR update ,
use the
.B \-r
option to retrieve revisions associated with a symbolic tag.
Use the
.B \-f
option to ignore all RCS files that do not contain the
tag.
Use the
.B \-p
option to prune directories that wind up empty because none
of their files matched the tag. Example:
.XS
cd ~/work
cvs checkout \-r V2_1 \-f \-p behemoth
.XE
.SS "Logging Changes"
It is a good idea to keep a change log together with the
sources. As a minimum, the change log should name and describe each
tagged release. The change log should also be under CVS control and
should be tagged along with the sources.
.LP
.BR cvslog (local)
can help. This command logs
changes reported during CVS
.B commit
operations. It automatically
updates a change log file in your working directory. When you are
finished making changes, you (optionally) edit the change log file and
then commit it to the master repository.
.LP
Note: You must edit the change log to describe a new release
and
.B commit
it to the master repository
.I before
.BR tag ging
the release using CVS. Otherwise, the release description will not be
included in the tagged package.
.LP
See
.BR cvslog (local)
for more information.
.SS "Merging a Subsequent Third-Party Distribution"
The initial steps in this process are identical to placing a
third-party distribution under CVS for the first time: save the
distribution kit and unpack the package in a scratch directory. From
that point the steps diverge.
The following example considers release 5.0 of the
Bugs-R-Us package.
.TP
\(bu
Check in the sources after unpacking them:
.XS
cd ~/scratch
checkin \-m 'Bugs-R-Us 5.0 distribution' bugs VENDOR V5_0 \\
| tee ~/WARNINGS
.XE
It is important to save the output of
.B checkin
in a file
because it lists the sources that have been locally modified.
It is best to save the file in a different directory (for example,
your home directory). Otherwise,
.B checkin
will try to check it into the master repository.
.TP
\(bu
In your usual working directory, check out a fresh copy of the
distribution that you just checked in.
.XS
cd ~/work
cvs checkout \-r VENDOR bugs
.XE
The
.B checkout
command shown above retrieves the latest revision on the vendor branch.
.TP
\(bu
See the `WARNINGS' file for a list of all locally modified
sources.
For each locally modified source,
look at the differences between
the new distribution and the latest local revision:
.XS
cvs diff \-r \fR\fILocalRev file\fR\fB
.XE
In this command,
.I LocalRev
is the latest
numeric or symbolic revision
on the RCS trunk of
.IR file .
You can use CVS
.B log
to get the revision history.
.TP
\(bu
If your local modifications to a file have been incorporated into
the vendor's distribution, then you should reset the default RCS
branch for that file to the vendor branch. CVS doesn't provide a
mechanism to do this. You have to do it by hand in the master
repository:
.XS
rcs \-bVENDOR \fR\fIfile\fR\fB,v
.XE
.TP
\(bu
If your local modifications need to be merged with the
new distribution, use CVS
.B join
to do it:
.XS
cvs join \-r VENDOR \fR\fIfile\fR\fB
.XE
The resulting file will be placed in your working directory.
Edit it to resolve any overlaps.
.TP
\(bu
Test the merged package.
.TP
\(bu
Commit all modified files to the repository:
.XS
cvs commit \-a
.XE
.TP
\(bu
Tag the repository with a new local tag.
.SS "Applying Patches to Third-Party Sources"
Patches are handled in a manner very similar to complete
third-party distributions. This example considers patches applied to
Bugs-R-Us release 5.0.
.TP
\(bu
Save the patch files together with the distribution kit
to which they apply.
The patch file names should clearly indicate the patch
level.
.TP
\(bu
In a scratch directory, check out the last `clean' vendor copy \- the
highest revision on the vendor branch with
.IR "no local changes" :
.XS
cd ~/scratch
cvs checkout \-r VENDOR bugs
.XE
.TP
\(bu
Use
.BR patch (local)
to apply the patches. You should now have an image of the
vendor's software just as though you had received a complete,
new release.
.TP
\(bu
Proceed with the steps described for merging a subsequent third-party
distribution.
.TP
\(bu
Note: When you get to the step that requires you
to check out the new distribution after you have
checked it into the vendor branch, you should move to a different
directory. Do not attempt to
.B checkout
files in the directory in
which you applied the patches. If you do, CVS will try to merge the
changes that you made during patching with the version being checked
out and things will get very confusing. Instead,
go to a different directory (like your working directory) and
check out the files there.
.SS "Advice to Third-Party Source Hackers"
As you can see from the preceding sections, merging local changes
into third-party distributions remains difficult, and probably
always will. This fact suggests some guidelines:
.TP
\(bu
Minimize local changes.
.I Never
make stylistic changes.
Change makefiles only as much as needed for installation. Avoid
overhauling anything. Pray that the vendor does the same.
.TP
\(bu
Avoid renaming files or moving them around.
.TP
\(bu
Put independent, locally written files like help documents, local
tools, or man pages in a sub-directory called `local-additions'.
Locally written files that are linked into an existing executable
should be added right in with the vendor's sources (not in a
`local-additions' directory).
If, in the future,
the vendor distributes something
equivalent to your locally written files
you can CVS
.B remove
the files from the `local-additions' directory at that time.
.SH SEE ALSO
.BR cvs (local),
.BR checkin (local),
.BR cvslog (local),
.BR cvscheck (local)
.SH AUTHOR
Lowell Skoog
.br
Software Technology Group
.br
Technical Computing

View File

@ -0,0 +1,116 @@
#! /bin/sh
# descend,v 1.1 1992/04/03 05:22:52 berliner Exp
#
# descend - walk down a directory tree and execute a command at each node
fullname=$0
name=descend
usage="Usage: $name [-afqrv] command [directory ...]\n
\040\040-a\040\040All: descend into directories starting with '.'\n
\040\040-f\040\040Force: ignore errors during descent\n
\040\040-q\040\040Quiet: don't print directory names\n
\040\040-r\040\040Restricted: don't descend into RCS, CVS.adm, SCCS directories\n
\040\040-v\040\040Verbose: print command before executing it"
# Scan for options
while getopts afqrv option; do
case $option in
a)
alldirs=$option
options=$options" "-$option
;;
f)
force=$option
options=$options" "-$option
;;
q)
verbose=
quiet=$option
options=$options" "-$option
;;
r)
restricted=$option
options=$options" "-$option
;;
v)
verbose=$option
quiet=
options=$options" "-$option
;;
\?)
/usr/5bin/echo $usage 1>&2
exit 1
;;
esac
done
shift `expr $OPTIND - 1`
# Get command to execute
if [ $# -lt 1 ] ; then
/usr/5bin/echo $usage 1>&2
exit 1
else
command=$1
shift
fi
# If no directory specified, use '.'
if [ $# -lt 1 ] ; then
default_dir=.
fi
# For each directory specified
for dir in $default_dir "$@" ; do
# Spawn sub-shell so we return to starting directory afterward
(cd $dir
# Execute specified command
if [ -z "$quiet" ] ; then
echo In directory `hostname`:`pwd`
fi
if [ -n "$verbose" ] ; then
echo $command
fi
eval "$command" || if [ -z "$force" ] ; then exit 1; fi
# Collect dot file names if necessary
if [ -n "$alldirs" ] ; then
dotfiles=.*
else
dotfiles=
fi
# For each file in current directory
for file in $dotfiles * ; do
# Skip '.' and '..'
if [ "$file" = "." -o "$file" = ".." ] ; then
continue
fi
# If a directory but not a symbolic link
if [ -d "$file" -a ! -h "$file" ] ; then
# If not skipping this type of directory
if [ \( "$file" != "RCS" -a \
"$file" != "SCCS" -a \
"$file" != "CVS" -a \
"$file" != "CVS.adm" \) \
-o -z "$restricted" ] ; then
# Recursively descend into it
$fullname $options "$command" "$file" \
|| if [ -z "$force" ] ; then exit 1; fi
fi
# Else if a directory AND a symbolic link
elif [ -d "$file" -a -h "$file" ] ; then
if [ -z "$quiet" ] ; then
echo In directory `hostname`:`pwd`/$file: symbolic link: skipping
fi
fi
done
) || if [ -z "$force" ] ; then exit 1; fi
done

View File

@ -0,0 +1,115 @@
.\" descend.man,v 1.1 1992/04/03 05:22:53 berliner Exp
.TH DESCEND 1 "31 March 1992"
.SH NAME
descend \- walk directory tree and execute a command at each node
.SH SYNOPSIS
.B descend
[
.B \-afqrv
]
.I command
[
.I directory
\&.\|.\|.
]
.SH DESCRIPTION
.B descend
walks down a directory tree and executes a command at each node. It
is not as versatile as
.BR find (1),
but it has a simpler syntax. If no
.I directory
is specified,
.B descend
starts at the current one.
.LP
Unlike
.BR find ,
.B descend
can be told to skip the special directories associated with RCS,
CVS, and SCCS. This makes
.B descend
especially handy for use with these packages. It can be used with
other commands too, of course.
.LP
.B descend
is a poor man's way to make any command recursive. Note:
.B descend
does not follow symbolic links to directories unless they are
specified on the command line.
.SH OPTIONS
.TP 15
.B \-a
.I All.
Descend into directories that begin with '.'.
.TP
.B \-f
.I Force.
Ignore errors during descent. Normally,
.B descend
quits when an error occurs.
.TP
.B \-q
.I Quiet.
Suppress the message `In directory
.IR directory '
that is normally printed during the descent.
.TP
.B \-r
.I Restricted.
Don't descend into the special directories
.SB RCS,
.SB CVS,
.SB CVS.adm,
and
.SB SCCS.
.TP
.B \-v
.I Verbose.
Print
.I command
before executing it.
.SH EXAMPLES
.TP 15
.B "descend ls"
Cheap substitute for `ls -R'.
.TP 15
.B "descend -f 'rm *' tree"
Strip `tree' of its leaves. This command descends the `tree'
directory, removing all regular files. Since
.BR rm (1)
does not remove directories, this command leaves the directory
structure of `tree' intact, but denuded. The
.B \-f
option is required to keep
.B descend
from quitting. You could use `rm \-f' instead.
.TP
.B "descend -r 'co RCS/*'" /project/src/
Check out every RCS file under the directory
.BR "/project/src" .
.TP
.B "descend -r 'cvs diff'"
Perform CVS `diff' operation on every directory below (and including)
the current one.
.SH DIAGNOSTICS
Returns 1 if errors occur (and the
.B \-f
option is not used). Otherwise returns 0.
.SH SEE ALSO
.BR find (1),
.BR rcsintro (1),
.BR cvs (1),
.BR sccs (1)
.SH AUTHOR
Lowell Skoog
.br
Software Technology Group
.br
John Fluke Mfg. Co., Inc.
.SH BUGS
Shell metacharacters in
.I command
may have bizarre effects. In particular, compound commands
(containing ';', '[', and ']' characters) will not work. It is best
to enclose complicated commands in single quotes \(aa\ \(aa.

View File

@ -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

View File

@ -0,0 +1,104 @@
#!/usr/bin/perl
# Modified by berliner@Sun.COM to add support for CVS 1.3 2/27/92
#
# Date: Tue, 6 Aug 91 13:27 EDT
# From: samborn@sunrise.com (Kevin Samborn)
#
# I revised the perl script I sent you yesterday to use the info you
# send in on stdin. (I am appending the newer script to the end)
#
# now the output looks like this:
#
# **************************************
# date: Tuesday, August 6, 1991 @ 13:17
# author: samborn
# Update of /elmer/cvs/CVSROOT.adm
# In directory astro:/home/samborn/CVSROOT.adm
#
# Modified Files:
# test3
#
# Added Files:
# test6
#
# Removed Files:
# test4
#
# Log Message:
# wow, what a test
#
# RCS: 1.4 /elmer/cvs/CVSROOT.adm/test3,v
# RCS: 1.1 /elmer/cvs/CVSROOT.adm/test6,v
# RCS: 1.1 /elmer/cvs/CVSROOT.adm/Attic/test4,v
#
#
# turn off setgid
#
$) = $(;
#
# parse command line arguments
#
@files = split(/ /,$ARGV[0]);
$logfile = $ARGV[1];
$cvsroot = $ENV{'CVSROOT'};
#
# Some date and time arrays
#
@mos = (January,February,March,April,May,June,July,August,September,
October,November,December);
@days = (Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday);
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime;
#
# get login name
#
$login = getlogin || (getpwuid($<))[0] || "nobody";
#
# open log file for appending
#
if ((open(OUT, ">>" . $logfile)) != 1) {
die "Could not open logfile " . $logfile . "\n";
}
#
# Header
#
print OUT "\n";
print OUT "**************************************\n";
print OUT "date: " . $days[$wday] . ", " . $mos[$mon] . " " . $mday . ", 19" . $year .
" @ " . $hour . ":" . sprintf("%02d", $min) . "\n";
print OUT "author: " . $login . "\n";
#
#print the stuff on stdin to the logfile
#
open(IN, "-");
while(<IN>) {
print OUT $_;
}
close(IN);
print OUT "\n";
#
# after log information, do an 'cvs -Qn status' on each file in the arguments.
#
for $file (@files[1..$#files]) {
if ($file eq "-") {
last;
}
open(RCS,"-|") || exec 'cvs', '-Qn', 'status', $file;
while (<RCS>) {
if (substr($_, 0, 7) eq " RCS") {
print OUT;
}
}
close (RCS);
}
close (OUT);

View File

@ -0,0 +1,331 @@
#!/usr/local/bin/perl -w
#
# Perl filter to handle the log messages from the checkin of files in
# a directory. This script will group the lists of files by log
# message, and mail a single consolidated log message at the end of
# the commit.
#
# This file assumes a pre-commit checking program that leaves the
# names of the first and last commit directories in a temporary file.
#
# Contributed by David Hampton <hampton@cisco.com>
#
############################################################
#
# Configurable options
#
############################################################
#
# Do cisco Systems, Inc. specific nonsense.
#
$cisco_systems = 1;
#
# Recipient of all mail messages
#
$mailto = "sw-notification@cisco.com";
############################################################
#
# Constants
#
############################################################
$STATE_NONE = 0;
$STATE_CHANGED = 1;
$STATE_ADDED = 2;
$STATE_REMOVED = 3;
$STATE_LOG = 4;
$LAST_FILE = "/tmp/#cvs.lastdir";
$CHANGED_FILE = "/tmp/#cvs.files.changed";
$ADDED_FILE = "/tmp/#cvs.files.added";
$REMOVED_FILE = "/tmp/#cvs.files.removed";
$LOG_FILE = "/tmp/#cvs.files.log";
$FILE_PREFIX = "#cvs.files";
$VERSION_FILE = "version";
$TRUNKREV_FILE = "TrunkRev";
$CHANGES_FILE = "Changes";
$CHANGES_TEMP = "Changes.tmp";
############################################################
#
# Subroutines
#
############################################################
sub format_names {
local($dir, @files) = @_;
local(@lines);
$lines[0] = sprintf(" %-08s", $dir);
foreach $file (@files) {
if (length($lines[$#lines]) + length($file) > 60) {
$lines[++$#lines] = sprintf(" %8s", " ");
}
$lines[$#lines] .= " ".$file;
}
@lines;
}
sub cleanup_tmpfiles {
local($all) = @_;
local($wd, @files);
$wd = `pwd`;
chdir("/tmp");
opendir(DIR, ".");
if ($all == 1) {
push(@files, grep(/$id$/, readdir(DIR)));
} else {
push(@files, grep(/^$FILE_PREFIX.*$id$/, readdir(DIR)));
}
closedir(DIR);
foreach (@files) {
unlink $_;
}
chdir($wd);
}
sub write_logfile {
local($filename, @lines) = @_;
open(FILE, ">$filename") || die ("Cannot open log file $filename.\n");
print(FILE join("\n", @lines), "\n");
close(FILE);
}
sub append_to_file {
local($filename, $dir, @files) = @_;
if (@files) {
local(@lines) = &format_names($dir, @files);
open(FILE, ">>$filename") || die ("Cannot open file $filename.\n");
print(FILE join("\n", @lines), "\n");
close(FILE);
}
}
sub write_line {
local($filename, $line) = @_;
open(FILE, ">$filename") || die("Cannot open file $filename.\n");
print(FILE $line, "\n");
close(FILE);
}
sub read_line {
local($line);
local($filename) = @_;
open(FILE, "<$filename") || die("Cannot open file $filename.\n");
$line = <FILE>;
close(FILE);
chop($line);
$line;
}
sub read_file {
local(@text);
local($filename, $leader) = @_;
open(FILE, "<$filename") || return ();
while (<FILE>) {
chop;
push(@text, sprintf(" %-10s %s", $leader, $_));
$leader = "";
}
close(FILE);
@text;
}
sub read_logfile {
local(@text);
local($filename, $leader) = @_;
open(FILE, "<$filename") || die ("Cannot open log file $filename.\n");
while (<FILE>) {
chop;
push(@text, $leader.$_);
}
close(FILE);
@text;
}
sub bump_version {
local($trunkrev, $editnum, $version);
$trunkrev = &read_line("$ENV{'CVSROOT'}/$repository/$TRUNKREV_FILE");
$editnum = &read_line("$ENV{'CVSROOT'}/$repository/$VERSION_FILE");
&write_line("$ENV{'CVSROOT'}/$repository/$VERSION_FILE", $editnum+1);
$version = $trunkrev . "(" . $editnum . ")";
}
sub build_header {
local($version) = @_;
local($header);
local($sec,$min,$hour,$mday,$mon,$year) = localtime(time);
$header = sprintf("%-8s %s %02d/%02d/%02d %02d:%02d:%02d",
$login, $version, $year%100, $mon+1, $mday,
$hour, $min, $sec);
}
sub do_changes_file {
local($changes, $tmpchanges);
local(@text) = @_;
$changes = "$ENV{'CVSROOT'}/$repository/$CHANGES_FILE";
$tmpchanges = "$ENV{'CVSROOT'}/$repository/$CHANGES_TEMP";
if (rename($changes, $tmpchanges) != 1) {
die("Cannot rename $changes to $tmpchanges.\n");
}
open(CHANGES, ">$changes") || die("Cannot open $changes.\n");
open(TMPCHANGES, "<$tmpchanges") || die("Cannot open $tmpchanges.\n");
print(CHANGES join("\n", @text), "\n\n");
print(CHANGES <TMPCHANGES>);
close(CHANGES);
close(TMPCHANGES);
unlink($tmpchanges);
}
sub mail_notification {
local($name, @text) = @_;
open(MAIL, "| mail -s \"Source Repository Modification\" $name");
print(MAIL join("\n", @text));
close(MAIL);
}
#############################################################
#
# Main Body
#
############################################################
#
# Initialize basic variables
#
$id = getpgrp();
$state = $STATE_NONE;
$login = getlogin || (getpwuid($<))[0] || die("Unknown user $<.\n");
@files = split(' ', $ARGV[0]);
@path = split('/', $files[0]);
$repository = @path[0];
if ($#path == 0) {
$dir = ".";
} else {
$dir = join('/', @path[1..$#path]);
}
#print("ARGV - ", join(":", @ARGV), "\n");
#print("files - ", join(":", @files), "\n");
#print("path - ", join(":", @path), "\n");
#print("dir - ", $dir, "\n");
#print("id - ", $id, "\n");
#
# Check for a new directory first. This will always appear as a
# single item in the argument list, and an empty log message.
#
if ($ARGV[0] =~ /New directory/) {
$version = &bump_version if ($cisco_systems != 0);
$header = &build_header($version);
@text = ();
push(@text, $header);
push(@text, "");
push(@text, " ".$ARGV[0]);
&do_changes_file(@text) if ($cisco_systems != 0);
&mail_notification($mailto, @text);
exit 0;
}
#
# Iterate over the body of the message collecting information.
#
while (<STDIN>) {
chop; # Drop the newline
if (/^Modified Files/) { $state = $STATE_CHANGED; next; }
if (/^Added Files/) { $state = $STATE_ADDED; next; }
if (/^Removed Files/) { $state = $STATE_REMOVED; next; }
if (/^Log Message/) { $state = $STATE_LOG; next; }
s/^[ \t\n]+//; # delete leading space
s/[ \t\n]+$//; # delete trailing space
push (@changed_files, split) if ($state == $STATE_CHANGED);
push (@added_files, split) if ($state == $STATE_ADDED);
push (@removed_files, split) if ($state == $STATE_REMOVED);
push (@log_lines, $_) if ($state == $STATE_LOG);
}
#
# Strip leading and trailing blank lines from the log message. Also
# compress multiple blank lines in the body of the message down to a
# single blank line.
#
while ($#log_lines > -1) {
last if ($log_lines[0] ne "");
shift(@log_lines);
}
while ($#log_lines > -1) {
last if ($log_lines[$#log_lines] ne "");
pop(@log_lines);
}
for ($i = $#log_lines; $i > 0; $i--) {
if (($log_lines[$i - 1] eq "") && ($log_lines[$i] eq "")) {
splice(@log_lines, $i, 1);
}
}
#
# Find the log file that matches this log message
#
for ($i = 0; ; $i++) {
last if (! -e "$LOG_FILE.$i.$id");
@text = &read_logfile("$LOG_FILE.$i.$id", "");
last if ($#text == -1);
last if (join(" ", @log_lines) eq join(" ", @text));
}
#
# Spit out the information gathered in this pass.
#
&write_logfile("$LOG_FILE.$i.$id", @log_lines);
&append_to_file("$ADDED_FILE.$i.$id", $dir, @added_files);
&append_to_file("$CHANGED_FILE.$i.$id", $dir, @changed_files);
&append_to_file("$REMOVED_FILE.$i.$id", $dir, @removed_files);
#
# Check whether this is the last directory. If not, quit.
#
$_ = &read_line("$LAST_FILE.$id");
exit 0 if (! grep(/$files[0]$/, $_));
#
# This is it. The commits are all finished. Lump everything together
# into a single message, fire a copy off to the mailing list, and drop
# it on the end of the Changes file.
#
# Get the full version number
#
$version = &bump_version if ($cisco_systems != 0);
$header = &build_header($version);
#
# Produce the final compilation of the log messages
#
@text = ();
push(@text, $header);
push(@text, "");
for ($i = 0; ; $i++) {
last if (! -e "$LOG_FILE.$i.$id");
push(@text, &read_file("$CHANGED_FILE.$i.$id", "Modified:"));
push(@text, &read_file("$ADDED_FILE.$i.$id", "Added:"));
push(@text, &read_file("$REMOVED_FILE.$i.$id", "Removed:"));
push(@text, " Log:");
push(@text, &read_logfile("$LOG_FILE.$i.$id", " "));
push(@text, "");
}
if ($cisco_systems != 0) {
@ddts = grep(/^CSCdi/, split(' ', join(" ", @text)));
$text[0] .= " " . join(" ", @ddts);
}
#
# Put the log message at the beginning of the Changes file and mail
# out the notification.
#
&do_changes_file(@text) if ($cisco_systems != 0);
&mail_notification($mailto, @text);
&cleanup_tmpfiles(1);
exit 0;

View File

@ -0,0 +1,87 @@
#!/usr/bin/perl
#
# From: clyne@niwot.scd.ucar.EDU (John Clyne)
# Date: Fri, 28 Feb 92 09:54:21 MST
#
# BTW, i wrote a perl script that is similar to 'nfpipe' except that in
# addition to logging to a file it provides a command line option for mailing
# change notices to a group of users. Obviously you probably wouldn't want
# to mail every change. But there may be certain directories that are commonly
# accessed by a group of users who would benefit from an email notice.
# Especially if they regularly beat on the same directory. Anyway if you
# think anyone would be interested here it is.
#
# mfpipe.pl,v 1.1 1992/03/02 01:22:41 berliner Exp
#
#
# File: mfpipe
#
# Author: John Clyne
# National Center for Atmospheric Research
# PO 3000, Boulder, Colorado
#
# Date: Wed Feb 26 18:34:53 MST 1992
#
# Description: Tee standard input to mail a list of users and to
# a file. Used by CVS logging.
#
# Usage: mfpipe [-f file] [user@host...]
#
# Environment: CVSROOT
# Path to CVS root.
#
# Files:
#
#
# Options: -f file
# Capture output to 'file'
#
$header = "Log Message:\n";
$mailcmd = "| mail -s 'CVS update notice'";
$whoami = `whoami`;
chop $whoami;
$date = `date`;
chop $date;
$cvsroot = $ENV{'CVSROOT'};
while (@ARGV) {
$arg = shift @ARGV;
if ($arg eq '-f') {
$file = shift @ARGV;
}
else {
$users = "$users $arg";
}
}
if ($users) {
$mailcmd = "$mailcmd $users";
open(MAIL, $mailcmd) || die "Execing $mail: $!\n";
}
if ($file) {
$logfile = "$cvsroot/LOG/$file";
open(FILE, ">> $logfile") || die "Opening $logfile: $!\n";
}
print FILE "$whoami $date--------BEGIN LOG ENTRY-------------\n" if ($logfile);
while (<>) {
print FILE $log if ($log && $logfile);
print FILE $_ if ($logfile);
print MAIL $_ if ($users);
$log = "log: " if ($_ eq $header);
}
close FILE;
die "Write failed" if $?;
close MAIL;
die "Mail failed" if $?;
exit 0;

View File

@ -0,0 +1,119 @@
Tue Apr 7 09:11:27 1992 Per Cederqvist (ceder@leopold)
* Release 1.02.
* pcl-cvs.el (cvs-diff-backup, cvs-edit-done, cvs-status): Call
save-some-buffers.
* pcl-cvs.el (cvs-diff-backup-extractor): Fixed syntax error.
* Makefile, README, compile-all.el, dist-makefile, pcl-cvs.el,
pcl-cvs.texinfo (XXRELEASEXX): A magic string that is substituted
for the current release number when a distribution is made.
(Release 1.01 says that it is release 1.00).
* pcl-cvs.el (cvs-find-file): Added missing pair of parenthesis.
Mon Mar 30 14:25:26 1992 Per Cederqvist (ceder@leopold)
* Release 1.01.
* pcl-cvs.el (cvs-parse-buffer): The message when waiting for a
lock has been changed.
Sun Mar 29 05:29:57 1992 Per Cederqvist (ceder@leopold)
* Release 1.00.
* pcl-cvs.el (cvs-do-update, cvs-sentinel, cvs-parse-buffer):
Major rewrite of buffer and window selection and handling.
The *cvs* buffer is now killed whenever a new "cvs update" is
initiated. The -update buffer is replaced with the *cvs*
buffer when the update is completed.
Sat Mar 28 21:03:05 1992 Per Cederqvist (ceder@robin)
* pcl-cvs.el (cvs-delete-unused-temporary-buffers): Fixed it.
* pcl-cvs.el (cvs-auto-remove-handled): New variable.
* pcl-cvs.el (cvs-edit-done): Use it.
* pcl-cvs.texinfo (Customization, Removing handled entries):
Document it.
* pcl-cvs.el (cvs-mode): Turn of the undo feature. It really
isn't useful in a cookie buffer...
* pcl-cvs.el (cvs-edit-done): Committing a file now looks more
like diffing a file. The window handling is better.
* pcl-cvs.el (cvs-use-temp-buffer): The &optional switch is no
longer needed.
Mon Mar 23 00:20:33 1992 Per Cederqvist (ceder@robin)
* Release 0.97.
* pcl-cvs.el (default-directory): Make sure it always ends in a
slash. fileinfo->dir does NOT end in a slash, and I had forgotten
to call file-name-as-directory in various places.
* pcl-cvs.el (cvs-diff-backup-extractor): Signal an error if a
fileinfo without backup file is given.
* pcl-cvs.el (cvs-mode): Added documentation.
* pcl-cvs.el (cvs-execute-list): Fix the order of files in the
same directory.
* pcl-cvs.el (cvs-log-flags, cvs-status-flags): New variables.
* pcl-cvs.el (cvs-log, cvs-status): Use them.
* pcl-cvs.texinfo (Customization): Document them.
* pcl-cvs.el (cvs-diff-backup): Filter non-backup-diffable files
at an earlier stage, like cvs-commit does.
* pcl-cvs.el (cvs-diff-flags): New variable.
* pcl-cvs.el (cvs-diff-backup): Use it.
* pcl-cvs.texinfo (Customization): Document it.
* pcl-cvs.el (cvs-execute-single-file-list): Remove &rest before
last argument. No callers needed updating.
* pcl-cvs.el (cvs-execute-list): Remove the &rest before the last
argument (constant-args). Update all callers of cvs-execute-list
to use the new calling convention.
* pcl-cvs.el (cvs-cvs-diff-flags): Now a list of strings instead
of a string.
* pcl-cvs.texinfo (Customization): Document the change to
cvs-cvs-diff-flags.
* Release 0.96.
* pcl-cvs.el (cvs-cvs-diff-flags): New variable.
* pcl-cvs.el (cvs-diff-cvs): Use it.
* pcl-cvs.texinfo (Customization, Viewing differences): Document it.
* pcl-cvs.el (cvs-use-temp-buffe): Don't switch to the temporary
buffer. Use display-buffer and set-buffer instead. This way
cvs-log, cvs-status, cvs-diff-cvs and friends don't select the
temporary buffer. The cursor will remain in the *cvs* buffer.
Sun Mar 22 21:50:18 1992 Per Cederqvist (ceder@robin)
* pcl-cvs.el (cvs-find-file, cvs-find-file-other-window): Don't
prompt when reading in a directory in dired.
* Makefile (pcl-cvs-$(VER)): Include pcl-cvs-startup.el in the
distribution.
* dist-makefile (pcl-cvs.dvi): Don't fail even if texindex does
not exist.
* pcl-cvs.texinfo (@setchapternewpage): Changed from 'off' to 'on'.
* pcl-cvs.texinfo (Variable index): Joined into function index.
* pcl-cvs.texinfo (Key index): add a description about the key.
* pcl-cvs.texinfo: Many other small changes.
Wed Mar 18 01:58:38 1992 Per Cederqvist (ceder@leopold)
* Use GNU General Public License version 2.

View File

@ -0,0 +1,83 @@
This text is copied from the TeXinfo manual for pcl-cvs.
Installation of the pcl-cvs program
===================================
1. Edit the file `Makefile' to reflect the situation at your site.
The only things you have to change is the definition of
`lispdir' and `infodir'. The elisp files will be copied to
`lispdir', and the info file to `infodir'.
2. Configure pcl-cvs.el
There are a couple of paths that you have to check to make
sure that they match you system. They appear early in the file
pcl-cvs.el.
*NOTE:* If your system is running emacs 18.57 or earlier
you MUST uncomment the line that says:
(setq delete-exited-processes nil)
Setting `delete-exited-processes' to `nil' works around a bug
in emacs that causes it to dump core. The bug was fixed in
emacs 18.58.
3. Type `make install' in the source directory. This will
byte-compile all `.el' files and copy both the `.el' and the
`.elc' into the directory you specified in step 1.
If you don't want to install the `.el' files but only the
`.elc' files (the byte-compiled files), you can type ``make
install_elc'' instead of ``make install''.
If you only want to create the compiled elisp files, but
don't want to install them, you can type `make elcfiles'
instead. This is what happens if you only type `make' without
parameters.
4. Edit the file `default.el' in your emacs lisp directory (usually
`/usr/gnu/emacs/lisp' or something similar) and enter the
contents of the file `pcl-cvs-startup.el' into it. It contains
a couple of `auto-load's that facilitates the use of pcl-cvs.
Installation of the on-line manual.
===================================
1. Create the info file `pcl-cvs' from `pcl-cvs.texinfo' by typing
`make info'. If you don't have the program `makeinfo' you can
get it by anonymous ftp from e.g. `ftp.gnu.ai.mit.edu' as
`pub/gnu/texinfo-2.14.tar.Z' (there might be a newer version
there when you read this), or you could use the preformatted
info file `pcl-cvs.info' that is included in the distribution
(type `cp pcl-cvs.info pcl-cvs').
2. Move the info file `pcl-cvs' to your standard info directory.
This might be called something like `/usr/gnu/emacs/info'.
3. Edit the file `dir' in the info directory and enter one line to
contain a pointer to the info file `pcl-cvs'. The line can, for
instance, look like this:
* Pcl-cvs: (pcl-cvs). An Emacs front-end to CVS.
How to make typeset documentation from pcl-cvs.texinfo
======================================================
If you have TeX installed at your site, you can make a typeset
manual from `pcl-cvs.texinfo'.
1. Run TeX by typing ``make pcl-cvs.dvi''. You will not get the
indices unless you have the `texindex' program.
2. Convert the resulting device independent file `pcl-cvs.dvi' to a
form which your printer can output and print it. If you have a
postscript printer there is a program, `dvi2ps', which does.
There is also a program which comes together with TeX, `dvips',
which you can use.

View File

@ -0,0 +1,78 @@
# Makefile,v 1.2 1992/04/07 20:49:07 berliner Exp
# Makefile for pcl-cvs release 1.02.
# Copyright (C) 1992 Per Cederqvist
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# This is the directory in which the ELFILES and ELCFILES will be
# installed.
lispdir = /usr/local/lib/elisp
# Where to install the info file.
prefix=/usr/local
infodir = $(prefix)/info
#
# The rest of this file should not need to be modified.
#
# Just in case...
SHELL = /bin/sh
ELFILES = pcl-cvs.el cookie.el elib-dll.el elib-node.el
ELCFILES = pcl-cvs.elc cookie.elc elib-dll.elc elib-node.elc
INFOFILES = pcl-cvs
TEXTMPS = pcl-cvs.aux pcl-cvs.log pcl-cvs.toc pcl-cvs.dvi pcl-cvs.cp \
pcl-cvs.fn pcl-cvs.vr pcl-cvs.tp pcl-cvs.ky pcl-cvs.pg \
pcl-cvs.cps pcl-cvs.fns pcl-cvs.kys pcl-cvs.pgs pcl-cvs.tps \
pcl-cvs.vrs
INSTALL = install
INSTALL_DATA = $(INSTALL)
elcfiles:
emacs -batch -l ./compile-all.el -f compile-pcl-cvs
all: elcfiles info
# Don't install the info file yet, since it requires makeinfo
# version 2.something (and version 1.something is distributed with emacs).
#
# install: install_elc install_info
install: install_elc
for i in $(ELFILES); do $(INSTALL_DATA) $$i $(lispdir)/$$i; done
install_elc: elcfiles
for i in $(ELCFILES); do $(INSTALL_DATA) $$i $(lispdir)/$$i; done
install_info: pcl-cvs
$(INSTALL_DATA) pcl-cvs $(infodir)/pcl-cvs
info pcl-cvs: pcl-cvs.texinfo
makeinfo +fill-column=70 pcl-cvs.texinfo
pcl-cvs.dvi: pcl-cvs.texinfo
tex pcl-cvs.texinfo
-texindex pcl-cvs.cp pcl-cvs.fn pcl-cvs.vr pcl-cvs.tp pcl-cvs.ky \
pcl-cvs.pg
tex pcl-cvs.texinfo
mostlyclean clean realclean:
rm -f *~ core $(ELCFILES) $(INFOFILES) $(TEXTMPS)
tags TAGS:
etags *.el

View File

@ -0,0 +1,14 @@
README,v 1.2 1992/04/07 20:49:09 berliner Exp
This is the readme file for pcl-cvs, release 1.02.
Pcl-cvs is a front-end to CVS version 1.3. It integrates the most
frequently used CVS commands into emacs.
There is some configuration that needs to be done in pcl-cvs.el to get
it to work. See the instructions in file INSTALL.
Full documentation is in pcl-cvs.texinfo. Since it requires makeinfo
2.14 a preformatted info file is also included (pcl-cvs.info).
ceder@lysator.liu.se

View File

@ -0,0 +1,52 @@
;;;; compile-all.el,v 1.2 1992/04/07 20:49:10 berliner Exp
;;;; This file byte-compiles all .el files in pcl-cvs release 1.02.
;;;;
;;;; Copyright (C) 1991 Inge Wallin
;;;;
;;;; This file is part of the GNU Emacs lisp library, Elib.
;;;;
;;;; GNU Elib is free software; you can redistribute it and/or modify
;;;; it under the terms of the GNU General Public License as published by
;;;; the Free Software Foundation; either version 1, or (at your option)
;;;; any later version.
;;;;
;;;; GNU Elib is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with GNU Emacs; see the file COPYING. If not, write to
;;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
;;;;
(setq elib-files '("elib-node"
"elib-dll"
"cookie"
"pcl-cvs"))
(defun compile-file-if-necessary (file)
"Compile the Elib file FILE if necessary.
This is done if FILE.el is newer than FILE.elc or if FILE.elc doesn't exist."
(let ((el-name (concat file ".el"))
(elc-name (concat file ".elc")))
(if (or (not (file-exists-p elc-name))
(file-newer-than-file-p el-name elc-name))
(progn
(message (format "Byte-compiling %s..." el-name))
(byte-compile-file el-name)))))
(defun compile-pcl-cvs ()
"Byte-compile all uncompiled files of elib.
Be sure to have . in load-path since a number of files in elib
depend on other files and we always want the newer one even if
a previous version of elib exists."
(interactive)
(setq load-path (append '(".") load-path))
(mapcar (function compile-file-if-necessary)
elib-files))

View File

@ -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)))

View File

@ -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)))))

View File

@ -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))))

View File

@ -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))))

View File

@ -0,0 +1,6 @@
;;; pcl-cvs-startup.el,v 1.2 1992/04/07 20:49:17 berliner Exp
(autoload 'cvs-update "pcl-cvs"
"Run a 'cvs update' in the current working directory. Feed the
output to a *cvs* buffer and run cvs-mode on it.
If optional prefix argument LOCAL is non-nil, 'cvs update -l' is run."
t)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,208 @@
#!/bin/csh
#
# rcs-to-cvs,v 1.3 1992/04/10 03:04:25 berliner Exp
# Contributed by Per Cederqvist <ceder@lysator.liu.se>.
#
# Copyright (c) 1989, Brian Berliner
#
# You may distribute under the terms of the GNU General Public License
# as specified in the README file that comes with the CVS 1.0 kit.
#
#############################################################################
# #
# This script is used to check in sources that previously was under RCS or #
# no source control system. #
# #
# Usage: rcs-to-cvs repository #
# #
# The repository is the directory where the sources should #
# be deposited.
# #
# checkin traverses the current directory, ensuring that an #
# identical directory structure exists in the repository directory. It #
# then checks the files in in the following manner: #
# #
# 1) If the file doesn't yet exist, check it in #
# as revision 0.1 #
# #
# The script also is somewhat verbose in letting the user know what is #
# going on. It prints a diagnostic when it creates a new file, or updates #
# a file that has been modified on the trunk. #
# #
#############################################################################
set vbose = 0
set message = ""
set cvsbin = /usr/gnu/bin
set rcsbin = /usr/gnu/bin
set grep = /bin/grep
set message_file = /usr/tmp/checkin.$$
set got_one = 0
if ( $#argv < 1 ) then
echo "Usage: rcs-to-cvs [-v] [-m message] [-f message_file] repository"
exit 1
endif
while ( $#argv )
switch ( $argv[1] )
case -v:
set vbose = 1
breaksw
case -m:
shift
echo $argv[1] > $message_file
set got_one = 1
breaksw
case -f:
shift
set message_file = $argv[1]
set got_one = 2
breaksw
default:
break
endsw
shift
end
if ( $#argv < 1 ) then
echo "Usage: rcs-to-cvs [-v] [-m message] [-f message_file] repository"
exit 1
endif
set repository = $argv[1]
shift
if ( ! $?CVSROOT ) then
echo "Please set the environmental variable CVSROOT to the root"
echo " of the tree you wish to update"
exit 1
endif
if ( $got_one == 0 ) then
echo "Please Edit this file to contain the RCS log information" >$message_file
echo "to be associated with this file (please remove these lines)">>$message_file
if ( $?EDITOR ) then
$EDITOR $message_file > /dev/tty
else
/usr/ucb/vi $message_file > /dev/tty
endif
set got_one = 1
endif
umask 22
set update_dir = ${CVSROOT}/${repository}
if ( -d SCCS ) then
echo SCCS files detected!
exit 1
endif
if ( -d RCS ) then
$rcsbin/co RCS/* >& /dev/null
endif
foreach name ( * .[a-zA-Z0-9]* )
echo $name
if ( "$name" == SCCS ) then
continue
endif
if ( "$name" == RCS ) then
continue
endif
if ( $vbose ) then
echo "Updating ${repository}/${name}"
endif
if ( -d "$name" ) then
if ( ! -d "${update_dir}/${name}" ) then
echo "WARNING: Creating new directory ${repository}/${name}"
mkdir "${update_dir}/${name}"
if ( $status ) then
echo "ERROR: mkdir failed - aborting"
exit 1
endif
endif
chdir "$name"
if ( $status ) then
echo "ERROR: Couldn\'t chdir to "$name" - aborting"
exit 1
endif
if ( $vbose ) then
rcs-to-cvs -v -f $message_file "${repository}/${name}"
else
rcs-to-cvs -f $message_file "${repository}/${name}"
endif
if ( $status ) then
exit 1
endif
chdir ..
else # if not directory
if ( ! -f "$name" ) then
echo "WARNING: "$name" is neither a regular file"
echo " nor a directory - ignored"
continue
endif
set file = "${update_dir}/${name},v"
set new = 0
set comment = ""
grep -s '\$Log.*\$' "${name}"
if ( $status == 0 ) then # If $Log keyword
set myext = ${name:e}
set knownext = 0
foreach xx ( "c" "csh" "e" "f" "h" "l" "mac" "me" "mm" "ms" "p" "r" "red" "s" "sh" "sl" "cl" "ml" "el" "tex" "y" "ye" "yr" "" )
if ( "${myext}" == "${xx}" ) then
set knownext = 1
break
endif
end
if ( $knownext == 0 ) then
echo For file ${file}:
grep '\$Log.*\$' "${name}"
echo -n "Please insert a comment leader for file ${name} > "
set comment = $<
endif
endif
if ( ! -f "$file" ) then # If not exists in repository
if ( ! -f "${update_dir}/Attic/${name},v" ) then
echo "WARNING: Creating new file ${repository}/${name}"
if ( -f RCS/"${name}",v ) then
echo "MSG: Copying old rcs file."
cp RCS/"${name}",v "$file"
else
if ( "${comment}" != "" ) then
$rcsbin/rcs -q -i -c"${comment}" -t${message_file} -m'.' "$file"
endif
$rcsbin/ci -q -u0.1 -t${message_file} -m'.' "$file"
if ( $status ) then
echo "ERROR: Initial check-in of $file failed - aborting"
exit 1
endif
set new = 1
endif
else
set file = "${update_dir}/Attic/${name},v"
echo "WARNING: IGNORED: ${repository}/Attic/${name}"
continue
endif
else # File existed
echo ERROR: File exists: Ignored: "$file"
continue
# set headbranch = `sed -n '/^head/p; /^branch/p; 2q' $file`
# if ( $#headbranch != 2 && $#headbranch != 4 ) then
# echo "ERROR: corrupted RCS file $file - aborting"
# endif
# set head = "$headbranch[2]"
# set branch = ""
# if ( $#headbranch == 4 ) then
# set branch = "$headbranch[4]"
# endif
# if ( "$head" == "1.1;" && "$branch" != "1.1.1;" ) then
# ${rcsbin}/rcsdiff -q -r1.1 $file > /dev/null
# if ( ! $status ) then
# set new = 1
# endif
# else
# if ( "$branch" != "1.1.1;" ) then
# echo -n "WARNING: Updating locally modified file "
# echo "${repository}/${name}"
# endif
# endif
endif
endif
end
if ( $got_one == 1 ) rm $message_file

View File

@ -0,0 +1,234 @@
#!/usr/bin/perl
# Author: John Rouillard (rouilj@cs.umb.edu)
# Supported: Yeah right. (Well what do you expect for 2 hours work?)
# Blame-to: rouilj@cs.umb.edu
# Complaints to: Anybody except Brian Berliner, he's blameless for
# this script.
# Acknowlegements: The base code for this script has been acquired
# from the log.pl script.
# rcslock.pl - A program to prevent commits when a file to be ckecked
# in is locked in the repository.
# There are times when you need exclusive access to a file. This
# often occurs when binaries are checked into the repository, since
# cvs's (actually rcs's) text based merging mechanism won't work. This
# script allows you to use the rcs lock mechanism (rcs -l) to make
# sure that no changes to a repository are able to be committed if
# those changes would result in a locked file being changed.
# WARNING:
# This script will work only if locking is set to strict.
#
# Setup:
# Add the following line to the commitinfo file:
# ALL /local/location/for/script/lockcheck [options]
# Where ALL is replaced by any suitable regular expression.
# Options are -v for verbose info, or -d for debugging info.
# The %s will provide the repository directory name and the names of
# all changed files.
# Use:
# When a developer needs exclusive access to a version of a file, s/he
# should use "rcs -l" in the repository tree to lock the version they
# are working on. CVS will automagically release the lock when the
# commit is performed.
# Method:
# An "rlog -h" is exec'ed to give info on all about to be
# committed files. This (header) information is parsed to determine
# if any locks are outstanding and what versions of the file are
# locked. This filename, version number info is used to index an
# associative array. All of the files to be committed are checked to
# see if any locks are outstanding. If locks are outstanding, the
# version number of the current file (taken from the CVS/Entries
# subdirectory) is used in the key to determine if that version is
# locked. If the file being checked in is locked by the person doing
# the checkin, the commit is allowed, but if the lock is held on that
# version of a file by another person, the commit is not allowed.
$ext = ",v"; # The extension on your rcs files.
$\="\n"; # I hate having to put \n's at the end of my print statements
$,=' '; # Spaces should occur between arguments to print when printed
# turn off setgid
#
$) = $(;
#
# parse command line arguments
#
require 'getopts.pl';
&Getopts("vd"); # verbose or debugging
# Verbose is useful when debugging
$opt_v = $opt_d if defined $opt_d;
# $files[0] is really the name of the subdirectory.
# @files = split(/ /,$ARGV[0]);
@files = @ARGV[0..$#ARGV];
$cvsroot = $ENV{'CVSROOT'};
#
# get login name
#
$login = getlogin || (getpwuid($<))[0] || "nobody";
#
# save the current directory since we have to return here to parse the
# CVS/Entries file if a lock is found.
#
$pwd = `/bin/pwd`;
chop $pwd;
print "Starting directory is $pwd" if defined $opt_d ;
#
# cd to the repository directory and check on the files.
#
print "Checking directory ", $files[0] if defined $opt_v ;
if ( $files[0] =~ /^\// )
{
print "Directory path is $files[0]" if defined $opt_d ;
chdir $files[0] || die "Can't change to repository directory $files[0]" ;
}
else
{
print "Directory path is $cvsroot/$files[0]" if defined $opt_d ;
chdir ($cvsroot . "/" . $files[0]) ||
die "Can't change to repository directory $files[0] in $cvsroot" ;
}
# Open the rlog process and apss all of the file names to that one
# process to cut down on exec overhead. This may backfire if there
# are too many files for the system buffer to handle, but if there are
# that many files, chances are that the cvs repository is not set up
# cleanly.
print "opening rlog -h @files[1..$#files] |" if defined $opt_d;
open( RLOG, "rlog -h @files[1..$#files] |") || die "Can't run rlog command" ;
# Create the locks associative array. The elements in the array are
# of two types:
#
# The name of the RCS file with a value of the total number of locks found
# for that file,
# or
#
# The name of the rcs file concatenated with the version number of the lock.
# The value of this element is the name of the locker.
# The regular expressions used to split the rcs info may have to be changed.
# The current ones work for rcs 5.6.
$lock = 0;
while (<RLOG>)
{
chop;
next if /^$/; # ditch blank lines
if ( $_ =~ /^RCS file: (.*)$/ )
{
$curfile = $1;
next;
}
if ( $_ =~ /^locks: strict$/ )
{
$lock = 1 ;
next;
}
if ( $lock )
{
# access list: is the line immediately following the list of locks.
if ( /^access list:/ )
{ # we are done getting lock info for this file.
$lock = 0;
}
else
{ # We are accumulating lock info.
# increment the lock count
$locks{$curfile}++;
# save the info on the version that is locked. $2 is the
# version number $1 is the name of the locker.
$locks{"$curfile" . "$2"} = $1
if /[ ]*([a-zA-Z._]*): ([0-9.]*)$/;
print "lock by $1 found on $curfile version $2" if defined $opt_d;
}
}
}
# Lets go back to the starting directory and see if any locked files
# are ones we are interested in.
chdir $pwd;
# fo all of the file names (remember $files[0] is the directory name
foreach $i (@files[1..$#files])
{
if ( defined $locks{$i . $ext} )
{ # well the file has at least one lock outstanding
# find the base version number of our file
&parse_cvs_entry($i,*entry);
# is our version of this file locked?
if ( defined $locks{$i . $ext . $entry{"version"}} )
{ # if so, it is by us?
if ( $login ne ($by = $locks{$i . $ext . $entry{"version"}}) )
{# crud somebody else has it locked.
$outstanding_lock++ ;
print "$by has file $i locked for version " , $entry{"version"};
}
else
{ # yeah I have it locked.
print "You have a lock on file $i for version " , $entry{"version"}
if defined $opt_v;
}
}
}
}
exit $outstanding_lock;
### End of main program
sub parse_cvs_entry
{ # a very simple minded hack at parsing an entries file.
local ( $file, *entry ) = @_;
local ( @pp );
open(ENTRIES, "< CVS/Entries") || die "Can't open entries file";
while (<ENTRIES>)
{
if ( $_ =~ /^\/$file\// )
{
@pp = split('/');
$entry{"name"} = $pp[1];
$entry{"version"} = $pp[2];
$entry{"dates"} = $pp[3];
$entry{"name"} = $pp[4];
$entry{"name"} = $pp[5];
$entry{"sticky"} = $pp[6];
return;
}
}
}

View File

@ -0,0 +1,277 @@
#!/bin/csh -f
#
# Sccs2rcs is a script to convert an existing SCCS
# history into an RCS history without losing any of
# the information contained therein.
# It has been tested under the following OS's:
# SunOS 3.5, 4.0.3, 4.1
# Ultrix-32 2.0, 3.1
#
# Things to note:
# + It will NOT delete or alter your ./SCCS history under any circumstances.
#
# + Run in a directory where ./SCCS exists and where you can
# create ./RCS
#
# + /usr/local/bin is put in front of the default path.
# (SCCS under Ultrix is set-uid sccs, bad bad bad, so
# /usr/local/bin/sccs here fixes that)
#
# + Date, time, author, comments, branches, are all preserved.
#
# + If a command fails somewhere in the middle, it bombs with
# a message -- remove what it's done so far and try again.
# "rm -rf RCS; sccs unedit `sccs tell`; sccs clean"
# There is no recovery and exit is far from graceful.
# If a particular module is hanging you up, consider
# doing it separately; move it from the current area so that
# the next run will have a better chance or working.
# Also (for the brave only) you might consider hacking
# the s-file for simpler problems: I've successfully changed
# the date of a delta to be in sync, then run "sccs admin -z"
# on the thing.
#
# + After everything finishes, ./SCCS will be moved to ./old-SCCS.
#
# This file may be copied, processed, hacked, mutilated, and
# even destroyed as long as you don't tell anyone you wrote it.
#
# Ken Cox
# Viewlogic Systems, Inc.
# kenstir@viewlogic.com
# ...!harvard!cg-atla!viewlog!kenstir
#
# Various hacks made by Brian Berliner before inclusion in CVS contrib area.
#
# sccs2rcs,v 1.1 1992/04/10 03:04:26 berliner Exp
#we'll assume the user set up the path correctly
# for the Pmax, /usr/ucb/sccs is suid sccs, what a pain
# /usr/local/bin/sccs should override /usr/ucb/sccs there
set path = (/usr/local/bin $path)
############################################################
# Error checking
#
if (! -w .) then
echo "Error: ./ not writeable by you."
exit 1
endif
if (! -d SCCS) then
echo "Error: ./SCCS directory not found."
exit 1
endif
set edits = (`sccs tell`)
if ($#edits) then
echo "Error: $#edits file(s) out for edit...clean up before converting."
exit 1
endif
if (-d RCS) then
echo "Warning: RCS directory exists"
if (`ls -a RCS | wc -l` > 2) then
echo "Error: RCS directory not empty
exit 1
endif
else
mkdir RCS
endif
sccs clean
set logfile = /tmp/sccs2rcs_$$_log
rm -f $logfile
set tmpfile = /tmp/sccs2rcs_$$_tmp
rm -f $tmpfile
set emptyfile = /tmp/sccs2rcs_$$_empty
echo -n "" > $emptyfile
set initialfile = /tmp/sccs2rcs_$$_init
echo "Initial revision" > $initialfile
set sedfile = /tmp/sccs2rcs_$$_sed
rm -f $sedfile
set revfile = /tmp/sccs2rcs_$$_rev
rm -f $revfile
# the quotes surround the dollar signs to fool RCS when I check in this script
set sccs_keywords = (\
'%W%[ ]*%G%'\
'%W%[ ]*%E%'\
'%W%'\
'%Z%%M%[ ]*%I%[ ]*%G%'\
'%Z%%M%[ ]*%I%[ ]*%E%'\
'%M%[ ]*%I%[ ]*%G%'\
'%M%[ ]*%I%[ ]*%E%'\
'%M%'\
'%I%'\
'%G%'\
'%E%'\
'%U%')
set rcs_keywords = (\
'$'Id'$'\
'$'Id'$'\
'$'Id'$'\
'$'SunId'$'\
'$'SunId'$'\
'$'Id'$'\
'$'Id'$'\
'$'RCSfile'$'\
'$'Revision'$'\
'$'Date'$'\
'$'Date'$'\
'')
############################################################
# Get some answers from user
#
echo ""
echo "Do you want to be prompted for a description of each"
echo "file as it is checked in to RCS initially?"
echo -n "(y=prompt for description, n=null description) [y] ?"
set ans = $<
if ((_$ans == _) || (_$ans == _y) || (_$ans == _Y)) then
set nodesc = 0
else
set nodesc = 1
endif
echo ""
echo "The default keyword substitutions are as follows and are"
echo "applied in the order specified:"
set i = 1
while ($i <= $#sccs_keywords)
# echo ' '\"$sccs_keywords[$i]\"' ==> '\"$rcs_keywords[$i]\"
echo " $sccs_keywords[$i] ==> $rcs_keywords[$i]"
@ i = $i + 1
end
echo ""
echo -n "Do you want to change them [n] ?"
set ans = $<
if ((_$ans != _) && (_$ans != _n) && (_$ans != _N)) then
echo "You can't always get what you want."
echo "Edit this script file and change the variables:"
echo ' $sccs_keywords'
echo ' $rcs_keywords'
else
echo "good idea."
endif
# create the sed script
set i = 1
while ($i <= $#sccs_keywords)
echo "s,$sccs_keywords[$i],$rcs_keywords[$i],g" >> $sedfile
@ i = $i + 1
end
onintr ERROR
############################################################
# Loop over every s-file in SCCS dir
#
foreach sfile (SCCS/s.*)
# get rid of the "s." at the beginning of the name
set file = `echo $sfile:t | sed -e "s/^..//"`
# work on each rev of that file in ascending order
set firsttime = 1
sccs prs $file | grep "^D " | awk '{print $2}' | sed -e 's/\./ /g' | sort -n -u +0 +1 +2 +3 +4 +5 +6 +7 +8 | sed -e 's/ /./g' > $revfile
foreach rev (`cat $revfile`)
if ($status != 0) goto ERROR
# get file into current dir and get stats
set date = `sccs prs -r$rev $file | grep "^D " | awk '{printf("19%s %s", $3, $4); exit}'`
set author = `sccs prs -r$rev $file | grep "^D " | awk '{print $5; exit}'`
echo ""
echo "==> file $file, rev=$rev, date=$date, author=$author"
sccs edit -r$rev $file >>& $logfile
if ($status != 0) goto ERROR
echo checked out of SCCS
# add RCS keywords in place of SCCS keywords
sed -f $sedfile $file > $tmpfile
if ($status != 0) goto ERROR
echo performed keyword substitutions
cp $tmpfile $file
# check file into RCS
if ($firsttime) then
set firsttime = 0
if ($nodesc) then
echo about to do ci
echo ci -f -r$rev -d"$date" -w$author -t$emptyfile $file
ci -f -r$rev -d"$date" -w$author -t$emptyfile $file < $initialfile >>& $logfile
if ($status != 0) goto ERROR
echo initial rev checked into RCS without description
else
echo ""
echo Enter a brief description of the file $file \(end w/ Ctrl-D\):
cat > $tmpfile
ci -f -r$rev -d"$date" -w$author -t$tmpfile $file < $initialfile >>& $logfile
if ($status != 0) goto ERROR
echo initial rev checked into RCS
endif
else
# get RCS lock
set lckrev = `echo $rev | sed -e 's/\.[0-9]*$//'`
if ("$lckrev" =~ [0-9]*.*) then
# need to lock the brach -- it is OK if the lock fails
rcs -l$lckrev $file >>& $logfile
else
# need to lock the trunk -- must succeed
rcs -l $file >>& $logfile
if ($status != 0) goto ERROR
endif
echo got lock
sccs prs -r$rev $file | grep "." > $tmpfile
# it's OK if grep fails here and gives status == 1
# put the delta message in $tmpfile
ed $tmpfile >>& $logfile <<EOF
/COMMENTS
1,.d
w
q
EOF
ci -f -r$rev -d"$date" -w$author $file < $tmpfile >>& $logfile
if ($status != 0) goto ERROR
echo checked into RCS
endif
sccs unedit $file >>& $logfile
if ($status != 0) goto ERROR
end
rm -f $file
end
############################################################
# Clean up
#
echo cleaning up...
mv SCCS old-SCCS
rm -f $tmpfile $emptyfile $initialfile $sedfile
echo ===================================================
echo " Conversion Completed Successfully"
echo ""
echo " SCCS history now in old-SCCS/"
echo ===================================================
set exitval = 0
goto cleanup
ERROR:
foreach f (`sccs tell`)
sccs unedit $f
end
echo ""
echo ""
echo Danger\! Danger\!
echo Some command exited with a non-zero exit status.
echo Log file exists in $logfile.
echo ""
echo Incomplete history in ./RCS -- remove it
echo Original unchanged history in ./SCCS
set exitval = 1
cleanup:
# leave log file
rm -f $tmpfile $emptyfile $initialfile $sedfile $revfile
exit $exitval

View File

@ -0,0 +1,18 @@
PROG = cvs
CFLAGS += -I${.CURDIR}/../lib \
-DDIRENT -DSTDC_HEADERS -DPOSIX -DBROKEN_SIGISMEMBER \
-DFTIME_MISSING -DHAVE_TIMEZONE -DUTIME_NULL_MISSING
LDADD= -L${.CURDIR}/../lib/obj -lcvs
SRCS = add.c admin.c checkin.c checkout.c classify.c commit.c \
create_adm.c diff.c entries.c find_names.c history.c ignore.c \
import.c lock.c log.c logmsg.c main.c rcs.c modules.c \
no_diff.c parseinfo.c patch.c recurse.c release.c remove.c repos.c rtag.c \
status.c tag.c update.c vers_ts.c version.c
MAN1= cvs.0
MAN5= cvs.0
.include <bsd.prog.mk>
.include "../../Makefile.inc"

447
gnu/usr.bin/cvs/cvs/add.c Normal file
View File

@ -0,0 +1,447 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* Add
*
* Adds a file or directory to the RCS source repository. For a file,
* the entry is marked as "needing to be added" in the user's own CVS
* directory, and really added to the repository when it is committed.
* For a directory, it is added at the appropriate place in the source
* repository and a CVS directory is generated within the directory.
*
* The -m option is currently the only supported option. Some may wish to
* supply standard "rcs" options here, but I've found that this causes more
* trouble than anything else.
*
* The user files or directories must already exist. For a directory, it must
* not already have a CVS file in it.
*
* An "add" on a file that has been "remove"d but not committed will cause the
* file to be resurrected.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)add.c 1.46 92/04/03";
#endif
#if __STDC__
static int add_directory (char *repository, char *dir);
static int build_entry (char *repository, char *user, char *options,
char *message, List * entries);
#else
static int add_directory ();
static int build_entry ();
#endif /* __STDC__ */
static char *add_usage[] =
{
"Usage: %s %s [-k rcs-kflag] [-m message] files...\n",
"\t-k\tUse \"rcs-kflag\" to add the file with the specified kflag.\n",
"\t-m\tUse \"message\" for the creation log.\n",
NULL
};
int
add (argc, argv)
int argc;
char *argv[];
{
char message[MAXMESGLEN];
char *user;
int i;
char *repository;
int c;
int err = 0;
int added_files = 0;
char *options = NULL;
List *entries;
Vers_TS *vers;
if (argc == 1 || argc == -1)
usage (add_usage);
/* parse args */
message[0] = '\0';
optind = 1;
while ((c = gnu_getopt (argc, argv, "k:m:")) != -1)
{
switch (c)
{
case 'k':
if (options)
free (options);
options = RCS_check_kflag (optarg);
break;
case 'm':
if (strlen (optarg) >= sizeof (message))
{
error (0, 0, "warning: message too long; truncated!");
(void) strncpy (message, optarg, sizeof (message));
message[sizeof (message) - 1] = '\0';
}
else
(void) strcpy (message, optarg);
break;
case '?':
default:
usage (add_usage);
break;
}
}
argc -= optind;
argv += optind;
if (argc <= 0)
usage (add_usage);
/* find the repository associated with our current dir */
repository = Name_Repository ((char *) NULL, (char *) NULL);
entries = ParseEntries (0);
/* walk the arg list adding files/dirs */
for (i = 0; i < argc; i++)
{
int begin_err = err;
user = argv[i];
if (index (user, '/') != NULL)
{
error (0, 0,
"cannot add files with '/' in their name; %s not added", user);
err++;
continue;
}
vers = Version_TS (repository, options, (char *) NULL, (char *) NULL,
user, 0, 0, entries, (List *) NULL);
if (vers->vn_user == NULL)
{
/* No entry available, ts_rcs is invalid */
if (vers->vn_rcs == NULL)
{
/* There is no RCS file either */
if (vers->ts_user == NULL)
{
/* There is no user file either */
error (0, 0, "nothing known about %s", user);
err++;
}
else if (!isdir (user))
{
/*
* See if a directory exists in the repository with
* the same name. If so, blow this request off.
*/
char dname[PATH_MAX];
(void) sprintf (dname, "%s/%s", repository, user);
if (isdir (dname))
{
error (0, 0,
"cannot add file `%s' since the directory",
user);
error (0, 0, "`%s' already exists in the repository",
dname);
error (1, 0, "illegal filename overlap");
}
/* There is a user file, so build the entry for it */
if (build_entry (repository, user, vers->options,
message, entries) != 0)
err++;
else if (!quiet)
{
added_files++;
error (0, 0, "scheduling file `%s' for addition",
user);
}
}
}
else
{
/*
* There is an RCS file already, so somebody else must've
* added it
*/
error (0, 0, "%s added independently by second party", user);
err++;
}
}
else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
{
/*
* An entry for a new-born file, ts_rcs is dummy, but that is
* inappropriate here
*/
error (0, 0, "%s has already been entered", user);
err++;
}
else if (vers->vn_user[0] == '-')
{
/* An entry for a removed file, ts_rcs is invalid */
if (vers->ts_user == NULL)
{
/* There is no user file (as it should be) */
if (vers->vn_rcs == NULL)
{
/*
* There is no RCS file, so somebody else must've removed
* it from under us
*/
error (0, 0,
"cannot resurrect %s; RCS file removed by second party", user);
err++;
}
else
{
/*
* There is an RCS file, so remove the "-" from the
* version number and restore the file
*/
char *tmp = xmalloc (strlen (user) + 50);
(void) strcpy (tmp, vers->vn_user + 1);
(void) strcpy (vers->vn_user, tmp);
(void) sprintf (tmp, "Resurrected %s", user);
Register (entries, user, vers->vn_user, tmp, vers->options,
vers->tag, vers->date);
free (tmp);
/* XXX - bugs here; this really resurrect the head */
if (update (2, argv + i - 1) == 0)
{
error (0, 0, "%s, version %s, resurrected", user,
vers->vn_user);
}
else
{
error (0, 0, "could not resurrect %s", user);
err++;
}
}
}
else
{
/* The user file shouldn't be there */
error (0, 0, "%s should be removed and is still there (or is back again)", user);
err++;
}
}
else
{
/* A normal entry, ts_rcs is valid, so it must already be there */
error (0, 0, "%s already exists, with version number %s", user,
vers->vn_user);
err++;
}
freevers_ts (&vers);
/* passed all the checks. Go ahead and add it if its a directory */
if (begin_err == err && isdir (user))
{
err += add_directory (repository, user);
continue;
}
}
if (added_files)
error (0, 0, "use 'cvs commit' to add %s permanently",
(added_files == 1) ? "this file" : "these files");
dellist (&entries);
return (err);
}
/*
* The specified user file is really a directory. So, let's make sure that
* it is created in the RCS source repository, and that the user's directory
* is updated to include a CVS directory.
*
* Returns 1 on failure, 0 on success.
*/
static int
add_directory (repository, dir)
char *repository;
char *dir;
{
char cwd[PATH_MAX], rcsdir[PATH_MAX];
char message[PATH_MAX + 100];
char *tag, *date;
if (index (dir, '/') != NULL)
{
error (0, 0,
"directory %s not added; must be a direct sub-directory", dir);
return (1);
}
if (strcmp (dir, CVSADM) == 0 || strcmp (dir, OCVSADM) == 0)
{
error (0, 0, "cannot add a `%s' or a `%s' directory", CVSADM, OCVSADM);
return (1);
}
/* before we do anything else, see if we have any per-directory tags */
ParseTag (&tag, &date);
/* now, remember where we were, so we can get back */
if (getwd (cwd) == NULL)
{
error (0, 0, "cannot get working directory: %s", cwd);
return (1);
}
if (chdir (dir) < 0)
{
error (0, errno, "cannot chdir to %s", dir);
return (1);
}
if (isfile (CVSADM) || isfile (OCVSADM))
{
error (0, 0,
"%s/%s (or %s/%s) already exists", dir, CVSADM, dir, OCVSADM);
goto out;
}
(void) sprintf (rcsdir, "%s/%s", repository, dir);
if (isfile (rcsdir) && !isdir (rcsdir))
{
error (0, 0, "%s is not a directory; %s not added", rcsdir, dir);
goto out;
}
/* setup the log message */
(void) sprintf (message, "Directory %s added to the repository\n", rcsdir);
if (tag)
{
(void) strcat (message, "--> Using per-directory sticky tag `");
(void) strcat (message, tag);
(void) strcat (message, "'\n");
}
if (date)
{
(void) strcat (message, "--> Using per-directory sticky date `");
(void) strcat (message, date);
(void) strcat (message, "'\n");
}
if (!isdir (rcsdir))
{
mode_t omask;
char line[MAXLINELEN];
Node *p;
List *ulist;
(void) printf ("Add directory %s to the repository (y/n) [n] ? ",
rcsdir);
(void) fflush (stdout);
clearerr (stdin);
if (fgets (line, sizeof (line), stdin) == NULL ||
(line[0] != 'y' && line[0] != 'Y'))
{
error (0, 0, "directory %s not added", rcsdir);
goto out;
}
omask = umask (2);
if (mkdir (rcsdir, 0777) < 0)
{
error (0, errno, "cannot mkdir %s", rcsdir);
(void) umask ((int) omask);
goto out;
}
(void) umask ((int) omask);
/*
* Set up an update list with a single title node for Update_Logfile
*/
ulist = getlist ();
p = getnode ();
p->type = UPDATE;
p->delproc = update_delproc;
p->key = xstrdup ("- New directory");
p->data = (char *) T_TITLE;
(void) addnode (ulist, p);
Update_Logfile (rcsdir, message, (char *) NULL, (FILE *) NULL, ulist);
dellist (&ulist);
}
Create_Admin (".", rcsdir, tag, date);
if (tag)
free (tag);
if (date)
free (date);
(void) printf ("%s", message);
out:
if (chdir (cwd) < 0)
error (1, errno, "cannot chdir to %s", cwd);
return (0);
}
/*
* Builds an entry for a new file and sets up "CVS/file",[pt] by
* interrogating the user. Returns non-zero on error.
*/
static int
build_entry (repository, user, options, message, entries)
char *repository;
char *user;
char *options;
char *message;
List *entries;
{
char fname[PATH_MAX];
char line[MAXLINELEN];
FILE *fp;
/*
* There may be an old file with the same name in the Attic! This is,
* perhaps, an awkward place to check for this, but other places are
* equally awkward.
*/
(void) sprintf (fname, "%s/%s/%s%s", repository, CVSATTIC, user, RCSEXT);
if (isreadable (fname))
{
error (0, 0, "there is an old file %s already in %s/%s", user,
repository, CVSATTIC);
return (1);
}
if (noexec)
return (0);
/*
* The options for the "add" command are store in the file CVS/user,p
*/
(void) sprintf (fname, "%s/%s%s", CVSADM, user, CVSEXT_OPT);
fp = open_file (fname, "w+");
if (fclose (fp) == EOF)
error(1, errno, "cannot close %s", fname);
/*
* And the requested log is read directly from the user and stored in the
* file user,t. If the "message" argument is set, use it as the
* initial creation log (which typically describes the file).
*/
(void) sprintf (fname, "%s/%s%s", CVSADM, user, CVSEXT_LOG);
fp = open_file (fname, "w+");
if (*message && fputs (message, fp) == EOF)
error (1, errno, "cannot write to %s", fname);
if (fclose(fp) == EOF)
error(1, errno, "cannot close %s", fname);
/*
* Create the entry now, since this allows the user to interrupt us above
* without needing to clean anything up (well, we could clean up the ,p
* and ,t files, but who cares).
*/
(void) sprintf (line, "Initial %s", user);
Register (entries, user, "0", line, options, (char *) 0, (char *) 0);
return (0);
}

124
gnu/usr.bin/cvs/cvs/admin.c Normal file
View File

@ -0,0 +1,124 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* Administration
*
* For now, this is basically a front end for rcs. All options are passed
* directly on.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)admin.c 1.17 92/03/31";
#endif
#if __STDC__
static Dtype admin_dirproc (char *dir, char *repos, char *update_dir);
static int admin_fileproc (char *file, char *update_dir,
char *repository, List *entries,
List *srcfiles);
#else
static int admin_fileproc ();
static Dtype admin_dirproc ();
#endif /* __STDC__ */
static char *admin_usage[] =
{
"Usage: %s %s rcs-options files...\n",
NULL
};
static int ac;
static char **av;
int
admin (argc, argv)
int argc;
char *argv[];
{
int err;
if (argc <= 1)
usage (admin_usage);
/* skip all optional arguments to see if we have any file names */
for (ac = 1; ac < argc; ac++)
if (argv[ac][0] != '-')
break;
argc -= ac;
av = argv + 1;
argv += ac;
ac--;
if (ac == 0 || argc == 0)
usage (admin_usage);
/* start the recursion processor */
err = start_recursion (admin_fileproc, (int (*) ()) NULL, admin_dirproc,
(int (*) ()) NULL, argc, argv, 0,
W_LOCAL, 0, 1, (char *) NULL, 1);
return (err);
}
/*
* Called to run "rcs" on a particular file.
*/
/* ARGSUSED */
static int
admin_fileproc (file, update_dir, repository, entries, srcfiles)
char *file;
char *update_dir;
char *repository;
List *entries;
List *srcfiles;
{
Vers_TS *vers;
char *version;
char **argv;
int argc;
int retcode = 0;
vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL,
file, 0, 0, entries, srcfiles);
version = vers->vn_user;
if (version == NULL)
return (0);
else if (strcmp (version, "0") == 0)
{
error (0, 0, "cannot admin newly added file `%s'", file);
return (0);
}
run_setup ("%s%s", Rcsbin, RCS);
for (argc = ac, argv = av; argc; argc--, argv++)
run_arg (*argv);
run_arg (vers->srcfile->path);
if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
{
if (!quiet)
error (0, retcode == -1 ? errno : 0,
"%s failed for `%s'", RCS, file);
return (1);
}
return (0);
}
/*
* Print a warm fuzzy message
*/
/* ARGSUSED */
static Dtype
admin_dirproc (dir, repos, update_dir)
char *dir;
char *repos;
char *update_dir;
{
if (!quiet)
error (0, 0, "Administrating %s", update_dir);
return (R_PROCESS);
}

View File

@ -0,0 +1,135 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* Check In
*
* Does a very careful checkin of the file "user", and tries not to spoil its
* modification time (to avoid needless recompilations). When RCS ID keywords
* get expanded on checkout, however, the modification time is updated and
* there is no good way to get around this.
*
* Returns non-zero on error.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)checkin.c 1.40 92/03/31";
#endif
int
Checkin (type, file, repository, rcs, rev, tag, message, entries)
int type;
char *file;
char *repository;
char *rcs;
char *rev;
char *tag;
char *message;
List *entries;
{
char fname[PATH_MAX];
Vers_TS *vers;
(void) printf ("Checking in %s;\n", file);
(void) sprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, file);
/*
* Move the user file to a backup file, so as to preserve its
* modification times, then place a copy back in the original file name
* for the checkin and checkout.
*/
if (!noexec)
copy_file (file, fname);
run_setup ("%s%s -f %s%s", Rcsbin, RCS_CI,
rev ? "-r" : "", rev ? rev : "");
run_args ("-m%s", message);
run_arg (rcs);
switch (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL))
{
case 0: /* everything normal */
/*
* The checkin succeeded, so now check the new file back out and
* see if it matches exactly with the one we checked in. If it
* does, just move the original user file back, thus preserving
* the modes; otherwise, we have no recourse but to leave the
* newly checkout file as the user file and remove the old
* original user file.
*/
/* XXX - make sure -k options are used on the co; and tag/date? */
run_setup ("%s%s -q %s%s", Rcsbin, RCS_CO,
rev ? "-r" : "", rev ? rev : "");
run_arg (rcs);
(void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
xchmod (file, 1);
if (xcmp (file, fname) == 0)
rename_file (fname, file);
else
(void) unlink_file (fname);
/*
* If we want read-only files, muck the permissions here, before
* getting the file time-stamp.
*/
if (cvswrite == FALSE)
xchmod (file, 0);
/* for added files with symbolic tags, need to add the tag too */
if (type == 'A' && tag && !isdigit (*tag))
{
run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, tag, rev);
run_arg (rcs);
(void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
}
/* re-register with the new data */
vers = Version_TS (repository, (char *) NULL, tag, (char *) NULL,
file, 1, 1, entries, (List *) NULL);
if (strcmp (vers->options, "-V4") == 0)
vers->options[0] = '\0';
Register (entries, file, vers->vn_rcs, vers->ts_user, vers->options,
vers->tag, vers->date);
history_write (type, (char *) 0, vers->vn_rcs, file, repository);
freevers_ts (&vers);
break;
case -1: /* fork failed */
if (!noexec)
error (1, errno, "could not check in %s -- fork failed", file);
return (1);
default: /* ci failed */
/*
* The checkin failed, for some unknown reason, so we restore the
* original user file, print an error, and return an error
*/
if (!noexec)
{
rename_file (fname, file);
error (0, 0, "could not check in %s", file);
}
return (1);
}
/*
* When checking in a specific revision, we may have locked the wrong
* branch, so to be sure, we do an extra unlock here before
* returning.
*/
if (rev)
{
run_setup ("%s%s -q -u", Rcsbin, RCS);
run_arg (rcs);
(void) run_exec (RUN_TTY, RUN_TTY, DEVNULL, RUN_NORMAL);
}
return (0);
}

View File

@ -0,0 +1,718 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* Create Version
*
* "checkout" creates a "version" of an RCS repository. This version is owned
* totally by the user and is actually an independent copy, to be dealt with
* as seen fit. Once "checkout" has been called in a given directory, it
* never needs to be called again. The user can keep up-to-date by calling
* "update" when he feels like it; this will supply him with a merge of his
* own modifications and the changes made in the RCS original. See "update"
* for details.
*
* "checkout" can be given a list of directories or files to be updated and in
* the case of a directory, will recursivley create any sub-directories that
* exist in the repository.
*
* When the user is satisfied with his own modifications, the present version
* can be committed by "commit"; this keeps the present version in tact,
* usually.
*
* The call is cvs checkout [options] <module-name>...
*
* "checkout" creates a directory ./CVS, in which it keeps its administration,
* in two files, Repository and Entries. The first contains the name of the
* repository. The second contains one line for each registered file,
* consisting of the version number it derives from, its time stamp at
* derivation time and its name. Both files are normal files and can be
* edited by the user, if necessary (when the repository is moved, e.g.)
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)checkout.c 1.67 92/04/10";
#endif
#if __STDC__
static char *findslash (char *start, char *p);
static int build_dirs_and_chdir (char *dir, char *prepath, char *realdir,
int sticky);
static int checkout_proc (int *pargc, char *argv[], char *where,
char *mwhere, char *mfile, int shorten,
int local_specified, char *omodule,
char *msg);
#else
static int checkout_proc ();
static char *findslash ();
static int build_dirs_and_chdir ();
#endif /* __STDC__ */
static char *checkout_usage[] =
{
"Usage:\n %s %s [-ANPQcflnpqs] [-r rev | -D date] [-d dir] [-k kopt] modules...\n",
"\t-A\tReset any sticky tags/date/kopts.\n",
"\t-N\tDon't shorten module paths if -d specified.\n",
"\t-P\tPrune empty directories.\n",
"\t-Q\tReally quiet.\n",
"\t-c\t\"cat\" the module database.\n",
"\t-f\tForce a head revision match if tag/date not found.\n",
"\t-l\tLocal directory only, not recursive\n",
"\t-n\tDo not run module program (if any).\n",
"\t-p\tCheck out files to standard output.\n",
"\t-q\tSomewhat quiet.\n",
"\t-s\tLike -c, but include module status.\n",
"\t-r rev\tCheck out revision or tag. (implies -P)\n",
"\t-D date\tCheck out revisions as of date. (implies -P)\n",
"\t-d dir\tCheck out into dir instead of module name.\n",
"\t-k kopt\tUse RCS kopt -k option on checkout.\n",
"\t-j rev\tMerge in changes made between current revision and rev.\n",
NULL
};
static char *export_usage[] =
{
"Usage: %s %s [-NPQflnq] [-r rev | -D date] [-d dir] module...\n",
"\t-N\tDon't shorten module paths if -d specified.\n",
"\t-Q\tReally quiet.\n",
"\t-f\tForce a head revision match if tag/date not found.\n",
"\t-l\tLocal directory only, not recursive\n",
"\t-n\tDo not run module program (if any).\n",
"\t-q\tSomewhat quiet.\n",
"\t-r rev\tCheck out revision or tag. (implies -P)\n",
"\t-D date\tCheck out revisions as of date. (implies -P)\n",
"\t-d dir\tCheck out into dir instead of module name.\n",
NULL
};
static int checkout_prune_dirs;
static int force_tag_match = 1;
static int pipeout;
static int aflag;
static char *options = NULL;
static char *tag = NULL;
static char *date = NULL;
static char *join_rev1 = NULL;
static char *join_rev2 = NULL;
static char *preload_update_dir = NULL;
int
checkout (argc, argv)
int argc;
char *argv[];
{
register int i;
int c;
DBM *db;
int cat = 0, err = 0, status = 0;
int run_module_prog = 1;
int local = 0;
int shorten = -1;
char *where = NULL;
char *valid_options, **valid_usage;
/*
* A smaller subset of options are allowed for the export command, which
* is essentially like checkout, except that it hard-codes certain
* options to be on (like -kv) and takes care to remove the CVS directory
* when it has done its duty
*/
if (strcmp (command_name, "export") == 0)
{
valid_options = "Nnd:flRQqr:D:";
valid_usage = export_usage;
}
else
{
valid_options = "ANnk:d:flRpQqcsr:D:j:P";
valid_usage = checkout_usage;
}
if (argc == -1)
usage (valid_usage);
ign_setup ();
optind = 1;
while ((c = gnu_getopt (argc, argv, valid_options)) != -1)
{
switch (c)
{
case 'A':
aflag = 1;
break;
case 'N':
shorten = 0;
break;
case 'k':
if (options)
free (options);
options = RCS_check_kflag (optarg);
break;
case 'n':
run_module_prog = 0;
break;
case 'Q':
really_quiet = 1;
/* FALL THROUGH */
case 'q':
quiet = 1;
break;
case 'l':
local = 1;
break;
case 'R':
local = 0;
break;
case 'P':
checkout_prune_dirs = 1;
break;
case 'p':
pipeout = 1;
run_module_prog = 0; /* don't run module prog when piping */
noexec = 1; /* so no locks will be created */
break;
case 'c':
cat = 1;
break;
case 'd':
where = optarg;
if (shorten == -1)
shorten = 1;
break;
case 's':
status = 1;
break;
case 'f':
force_tag_match = 0;
break;
case 'r':
tag = optarg;
checkout_prune_dirs = 1;
break;
case 'D':
date = Make_Date (optarg);
checkout_prune_dirs = 1;
break;
case 'j':
if (join_rev2)
error (1, 0, "only two -j options can be specified");
if (join_rev1)
join_rev2 = optarg;
else
join_rev1 = optarg;
break;
case '?':
default:
usage (valid_usage);
break;
}
}
argc -= optind;
argv += optind;
if (shorten == -1)
shorten = 0;
if ((!(cat + status) && argc == 0) || ((cat + status) && argc != 0)
|| (tag && date))
usage (valid_usage);
if (where && pipeout)
error (1, 0, "-d and -p are mutually exclusive");
if (strcmp (command_name, "export") == 0)
{
if (!tag && !date)
{
error (0, 0, "must specify a tag or date");
usage (valid_usage);
}
if (tag && isdigit (tag[0]))
error (1, 0, "tag `%s' must be a symbolic tag", tag);
options = RCS_check_kflag ("v");/* -kv must be on */
}
if (cat || status)
{
cat_module (status);
return (0);
}
db = open_module ();
/*
* if we have more than one argument and where was specified, we make the
* where, cd into it, and try to shorten names as much as possible.
* Otherwise, we pass the where as a single argument to do_module.
*/
if (argc > 1 && where != NULL)
{
char repository[PATH_MAX];
(void) mkdir (where, 0777);
if (chdir (where) < 0)
error (1, errno, "cannot chdir to %s", where);
preload_update_dir = xstrdup (where);
where = (char *) NULL;
if (!isfile (CVSADM) && !isfile (OCVSADM))
{
(void) sprintf (repository, "%s/%s", CVSroot, CVSNULLREPOS);
if (!isfile (repository))
(void) mkdir (repository, 0777);
Create_Admin (".", repository, (char *) NULL, (char *) NULL);
if (!noexec)
{
FILE *fp;
fp = open_file (CVSADM_ENTSTAT, "w+");
if (fclose(fp) == EOF)
error(1, errno, "cannot close %s", CVSADM_ENTSTAT);
}
}
}
/*
* if where was specified (-d) and we have not taken care of it already
* with the multiple arg stuff, and it was not a simple directory name
* but rather a path, we strip off everything but the last component and
* attempt to cd to the indicated place. where then becomes simply the
* last component
*/
if (where != NULL && index (where, '/') != NULL)
{
char *slash;
slash = rindex (where, '/');
*slash = '\0';
if (chdir (where) < 0)
error (1, errno, "cannot chdir to %s", where);
preload_update_dir = xstrdup (where);
where = slash + 1;
if (*where == '\0')
where = NULL;
}
for (i = 0; i < argc; i++)
err += do_module (db, argv[i], CHECKOUT, "Updating", checkout_proc,
where, shorten, local, run_module_prog,
(char *) NULL);
close_module (db);
return (err);
}
/*
* process_module calls us back here so we do the actual checkout stuff
*/
/* ARGSUSED */
static int
checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
local_specified, omodule, msg)
int *pargc;
char *argv[];
char *where;
char *mwhere;
char *mfile;
int shorten;
int local_specified;
char *omodule;
char *msg;
{
int err = 0;
int which;
char *cp;
char *cp2;
char repository[PATH_MAX];
char xwhere[PATH_MAX];
char *oldupdate = NULL;
char *prepath;
char *realdirs;
/*
* OK, so we're doing the checkout! Our args are as follows:
* argc,argv contain either dir or dir followed by a list of files
* where contains where to put it (if supplied by checkout)
* mwhere contains the module name or -d from module file
* mfile says do only that part of the module
* shorten = TRUE says shorten as much as possible
* omodule is the original arg to do_module()
*/
/* set up the repository (maybe) for the bottom directory */
(void) sprintf (repository, "%s/%s", CVSroot, argv[0]);
/* save the original value of preload_update_dir */
if (preload_update_dir != NULL)
oldupdate = xstrdup (preload_update_dir);
/* fix up argv[] for the case of partial modules */
if (mfile != NULL)
{
char file[PATH_MAX];
/* if mfile is really a path, straighten it out first */
if ((cp = rindex (mfile, '/')) != NULL)
{
*cp = 0;
(void) strcat (repository, "/");
(void) strcat (repository, mfile);
/*
* Now we need to fill in the where correctly. if !shorten, tack
* the rest of the path onto where if where is filled in
* otherwise tack the rest of the path onto mwhere and make that
* the where
*
* If shorten is enabled, we might use mwhere to set where if
* nobody set it yet, so we'll need to setup mwhere as the last
* component of the path we are tacking onto repository
*/
if (!shorten)
{
if (where != NULL)
(void) sprintf (xwhere, "%s/%s", where, mfile);
else
(void) sprintf (xwhere, "%s/%s", mwhere, mfile);
where = xwhere;
}
else
{
char *slash;
if ((slash = rindex (mfile, '/')) != NULL)
mwhere = slash + 1;
else
mwhere = mfile;
}
mfile = cp + 1;
}
(void) sprintf (file, "%s/%s", repository, mfile);
if (isdir (file))
{
/*
* The portion of a module was a directory, so kludge up where to
* be the subdir, and fix up repository
*/
(void) strcpy (repository, file);
/*
* At this point, if shorten is not enabled, we make where either
* where with mfile concatenated, or if where hadn't been set we
* set it to mwhere with mfile concatenated.
*
* If shorten is enabled and where hasn't been set yet, then where
* becomes mfile
*/
if (!shorten)
{
if (where != NULL)
(void) sprintf (xwhere, "%s/%s", where, mfile);
else
(void) sprintf (xwhere, "%s/%s", mwhere, mfile);
where = xwhere;
}
else if (where == NULL)
where = mfile;
}
else
{
int i;
/*
* The portion of a module was a file, so kludge up argv to be
* correct
*/
for (i = 1; i < *pargc; i++)/* free the old ones */
free (argv[i]);
argv[1] = xstrdup (mfile); /* set up the new one */
*pargc = 2;
/* where gets mwhere if where isn't set */
if (where == NULL)
where = mwhere;
}
}
/*
* if shorten is enabled and where isn't specified yet, we pluck the last
* directory component of argv[0] and make it the where
*/
if (shorten && where == NULL)
{
if ((cp = rindex (argv[0], '/')) != NULL)
{
(void) strcpy (xwhere, cp + 1);
where = xwhere;
}
}
/* if where is still NULL, use mwhere if set or the argv[0] dir */
if (where == NULL)
{
if (mwhere)
where = mwhere;
else
{
(void) strcpy (xwhere, argv[0]);
where = xwhere;
}
}
if (preload_update_dir != NULL)
{
char tmp[PATH_MAX];
(void) sprintf (tmp, "%s/%s", preload_update_dir, where);
free (preload_update_dir);
preload_update_dir = xstrdup (tmp);
}
else
preload_update_dir = xstrdup (where);
/*
* At this point, where is the directory we want to build, repository is
* the repository for the lowest level of the path.
*/
/*
* If we are sending everything to stdout, we can skip a whole bunch of
* work from here
*/
if (!pipeout)
{
/*
* We need to tell build_dirs not only the path we want it to build,
* but also the repositories we want it to populate the path with. To
* accomplish this, we pass build_dirs a ``real path'' with valid
* repositories and a string to pre-pend based on how many path
* elements exist in where. Big Black Magic
*/
prepath = xstrdup (repository);
cp = rindex (where, '/');
cp2 = rindex (prepath, '/');
while (cp != NULL)
{
cp = findslash (where, cp - 1);
cp2 = findslash (prepath, cp2 - 1);
}
*cp2 = '\0';
realdirs = cp2 + 1;
/*
* build dirs on the path if necessary and leave us in the bottom
* directory (where if where was specified) doesn't contain a CVS
* subdir yet, but all the others contain CVS and Entries.Static
* files
*/
if (build_dirs_and_chdir (where, prepath, realdirs, *pargc <= 1) != 0)
{
error (0, 0, "ignoring module %s", omodule);
free (prepath);
free (preload_update_dir);
preload_update_dir = oldupdate;
return (1);
}
/* clean up */
free (prepath);
/* set up the repository (or make sure the old one matches) */
if (!isfile (CVSADM) && !isfile (OCVSADM))
{
FILE *fp;
if (!noexec && *pargc > 1)
{
Create_Admin (".", repository, (char *) NULL, (char *) NULL);
fp = open_file (CVSADM_ENTSTAT, "w+");
if (fclose(fp) == EOF)
error(1, errno, "cannot close %s", CVSADM_ENTSTAT);
}
else
Create_Admin (".", repository, tag, date);
}
else
{
char *repos;
/* get the contents of the previously existing repository */
repos = Name_Repository ((char *) NULL, preload_update_dir);
if (strcmp (repository, repos) != 0)
{
error (0, 0, "existing repository %s does not match %s",
repos, repository);
error (0, 0, "ignoring module %s", omodule);
free (repos);
free (preload_update_dir);
preload_update_dir = oldupdate;
return (1);
}
free (repos);
}
}
/*
* If we are going to be updating to stdout, we need to cd to the
* repository directory so the recursion processor can use the current
* directory as the place to find repository information
*/
if (pipeout)
{
if (chdir (repository) < 0)
{
error (0, errno, "cannot chdir to %s", repository);
free (preload_update_dir);
preload_update_dir = oldupdate;
return (1);
}
which = W_REPOS;
}
else
which = W_LOCAL | W_REPOS;
if (tag != NULL || date != NULL)
which |= W_ATTIC;
/*
* if we are going to be recursive (building dirs), go ahead and call the
* update recursion processor. We will be recursive unless either local
* only was specified, or we were passed arguments
*/
if (!(local_specified || *pargc > 1))
{
if (strcmp (command_name, "export") != 0 && !pipeout)
history_write ('O', preload_update_dir, tag ? tag : date, where,
repository);
err += do_update (0, (char **) NULL, options, tag, date,
force_tag_match, 0 /* !local */ ,
1 /* update -d */ , aflag, checkout_prune_dirs,
pipeout, which, join_rev1, join_rev2,
preload_update_dir);
free (preload_update_dir);
preload_update_dir = oldupdate;
return (err);
}
if (!pipeout)
{
int i;
List *entries;
/* we are only doing files, so register them */
entries = ParseEntries (0);
for (i = 1; i < *pargc; i++)
{
char line[MAXLINELEN];
char *user;
Vers_TS *vers;
user = argv[i];
vers = Version_TS (repository, options, tag, date, user,
force_tag_match, 0, entries, (List *) NULL);
if (vers->ts_user == NULL)
{
(void) sprintf (line, "Initial %s", user);
Register (entries, user, vers->vn_rcs, line, vers->options,
vers->tag, vers->date);
}
freevers_ts (&vers);
}
dellist (&entries);
}
/* Don't log "export", just regular "checkouts" */
if (strcmp (command_name, "export") != 0 && !pipeout)
history_write ('O', preload_update_dir, (tag ? tag : date), where,
repository);
/* go ahead and call update now that everything is set */
err += do_update (*pargc - 1, argv + 1, options, tag, date,
force_tag_match, local_specified, 1 /* update -d */,
aflag, checkout_prune_dirs, pipeout, which, join_rev1,
join_rev2, preload_update_dir);
free (preload_update_dir);
preload_update_dir = oldupdate;
return (err);
}
static char *
findslash (start, p)
char *start;
char *p;
{
while ((int) p >= (int) start && *p != '/')
p--;
if ((int) p < (int) start)
return (NULL);
else
return (p);
}
/*
* build all the dirs along the path to dir with CVS subdirs with appropriate
* repositories and Entries.Static files
*/
static int
build_dirs_and_chdir (dir, prepath, realdir, sticky)
char *dir;
char *prepath;
char *realdir;
int sticky;
{
FILE *fp;
char repository[PATH_MAX];
char path[PATH_MAX];
char path2[PATH_MAX];
char *slash;
char *slash2;
char *cp;
char *cp2;
(void) strcpy (path, dir);
(void) strcpy (path2, realdir);
for (cp = path, cp2 = path2;
(slash = index (cp, '/')) != NULL && (slash2 = index (cp2, '/')) != NULL;
cp = slash + 1, cp2 = slash2 + 1)
{
*slash = '\0';
*slash2 = '\0';
(void) mkdir (cp, 0777);
if (chdir (cp) < 0)
{
error (0, errno, "cannot chdir to %s", cp);
return (1);
}
if (!isfile (CVSADM) && !isfile (OCVSADM) &&
strcmp (command_name, "export") != 0)
{
(void) sprintf (repository, "%s/%s", prepath, path2);
Create_Admin (".", repository, sticky ? (char *) NULL : tag,
sticky ? (char *) NULL : date);
if (!noexec)
{
fp = open_file (CVSADM_ENTSTAT, "w+");
if (fclose(fp) == EOF)
error(1, errno, "cannot close %s", CVSADM_ENTSTAT);
}
}
*slash = '/';
*slash2 = '/';
}
(void) mkdir (cp, 0777);
if (chdir (cp) < 0)
{
error (0, errno, "cannot chdir to %s", cp);
return (1);
}
return (0);
}

View File

@ -0,0 +1,380 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)classify.c 1.11 92/03/31";
#endif
#if __STDC__
static void sticky_ck (char *file, int aflag, Vers_TS * vers, List * entries);
#else
static void sticky_ck ();
#endif /* __STDC__ */
/*
* Classify the state of a file
*/
Ctype
Classify_File (file, tag, date, options, force_tag_match, aflag, repository,
entries, srcfiles, versp)
char *file;
char *tag;
char *date;
char *options;
int force_tag_match;
int aflag;
char *repository;
List *entries;
List *srcfiles;
Vers_TS **versp;
{
Vers_TS *vers;
Ctype ret;
/* get all kinds of good data about the file */
vers = Version_TS (repository, options, tag, date, file,
force_tag_match, 0, entries, srcfiles);
if (vers->vn_user == NULL)
{
/* No entry available, ts_rcs is invalid */
if (vers->vn_rcs == NULL)
{
/* there is no RCS file either */
if (vers->ts_user == NULL)
{
/* there is no user file */
if (!force_tag_match || !(vers->tag || vers->date))
if (!really_quiet)
error (0, 0, "nothing known about %s", file);
ret = T_UNKNOWN;
}
else
{
/* there is a user file */
if (!force_tag_match || !(vers->tag || vers->date))
if (!really_quiet)
error (0, 0, "use `cvs add' to create an entry for %s",
file);
ret = T_UNKNOWN;
}
}
else
{
/* there is an rcs file */
if (vers->ts_user == NULL)
{
/* There is no user file; needs checkout */
ret = T_CHECKOUT;
}
else
{
/*
* There is a user file; print a warning and add it to the
* conflict list, only if it is indeed different from what we
* plan to extract
*/
if (No_Difference (file, vers, entries))
{
/* the files were different so it is a conflict */
if (!really_quiet)
error (0, 0, "move away %s; it is in the way", file);
ret = T_CONFLICT;
}
else
/* since there was no difference, still needs checkout */
ret = T_CHECKOUT;
}
}
}
else if (strcmp (vers->vn_user, "0") == 0)
{
/* An entry for a new-born file; ts_rcs is dummy */
if (vers->ts_user == NULL)
{
/*
* There is no user file, but there should be one; remove the
* entry
*/
if (!really_quiet)
error (0, 0, "warning: new-born %s has disappeared", file);
ret = T_REMOVE_ENTRY;
}
else
{
/* There is a user file */
if (vers->vn_rcs == NULL)
/* There is no RCS file, added file */
ret = T_ADDED;
else
{
/*
* There is an RCS file, so someone else must have checked
* one in behind our back; conflict
*/
if (!really_quiet)
error (0, 0,
"conflict: %s created independently by second party",
file);
ret = T_CONFLICT;
}
}
}
else if (vers->vn_user[0] == '-')
{
/* An entry for a removed file, ts_rcs is invalid */
if (vers->ts_user == NULL)
{
char tmp[PATH_MAX];
/* There is no user file (as it should be) */
(void) sprintf (tmp, "-%s", vers->vn_rcs ? vers->vn_rcs : "");
if (vers->vn_rcs == NULL)
{
/*
* There is no RCS file; this is all-right, but it has been
* removed independently by a second party; remove the entry
*/
ret = T_REMOVE_ENTRY;
}
else if (strcmp (tmp, vers->vn_user) == 0)
/*
* The RCS file is the same version as the user file was, and
* that's OK; remove it
*/
ret = T_REMOVED;
else
{
/*
* The RCS file is a newer version than the removed user file
* and this is definitely not OK; make it a conflict.
*/
if (!really_quiet)
error (0, 0,
"conflict: removed %s was modified by second party",
file);
ret = T_CONFLICT;
}
}
else
{
/* The user file shouldn't be there */
if (!really_quiet)
error (0, 0, "%s should be removed and is still there", file);
ret = T_REMOVED;
}
}
else
{
/* A normal entry, TS_Rcs is valid */
if (vers->vn_rcs == NULL)
{
/* There is no RCS file */
if (vers->ts_user == NULL)
{
/* There is no user file, so just remove the entry */
if (!really_quiet)
error (0, 0, "warning: %s is not (any longer) pertinent",
file);
ret = T_REMOVE_ENTRY;
}
else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
{
/*
* The user file is still unmodified, so just remove it from
* the entry list
*/
if (!really_quiet)
error (0, 0, "%s is no longer in the repository", file);
ret = T_REMOVE_ENTRY;
}
else
{
/*
* The user file has been modified and since it is no longer
* in the repository, a conflict is raised
*/
if (No_Difference (file, vers, entries))
{
/* they are different -> conflict */
if (!really_quiet)
error (0, 0,
"conflict: %s is modified but no longer in the repository",
file);
ret = T_CONFLICT;
}
else
{
/* they weren't really different */
if (!really_quiet)
error (0, 0,
"warning: %s is not (any longer) pertinent",
file);
ret = T_REMOVE_ENTRY;
}
}
}
else if (strcmp (vers->vn_rcs, vers->vn_user) == 0)
{
/* The RCS file is the same version as the user file */
if (vers->ts_user == NULL)
{
/*
* There is no user file, so note that it was lost and
* extract a new version
*/
if (strcmp (command_name, "update") == 0)
if (!really_quiet)
error (0, 0, "warning: %s was lost", file);
ret = T_CHECKOUT;
}
else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
{
/*
* The user file is still unmodified, so nothing special at
* all to do -- no lists updated, unless the sticky -k option
* has changed. If the sticky tag has changed, we just need
* to re-register the entry
*/
if (vers->entdata->options &&
strcmp (vers->entdata->options, vers->options) != 0)
ret = T_CHECKOUT;
else
{
sticky_ck (file, aflag, vers, entries);
ret = T_UPTODATE;
}
}
else
{
/*
* The user file appears to have been modified, but we call
* No_Difference to verify that it really has been modified
*/
if (No_Difference (file, vers, entries))
{
/*
* they really are different; modified if we aren't
* changing any sticky -k options, else needs merge
*/
#ifdef XXX_FIXME_WHEN_RCSMERGE_IS_FIXED
if (strcmp (vers->entdata->options ?
vers->entdata->options : "", vers->options) == 0)
ret = T_MODIFIED;
else
ret = T_NEEDS_MERGE;
#else
ret = T_MODIFIED;
sticky_ck (file, aflag, vers, entries);
#endif
}
else
{
/* file has not changed; check out if -k changed */
if (strcmp (vers->entdata->options ?
vers->entdata->options : "", vers->options) != 0)
{
ret = T_CHECKOUT;
}
else
{
/*
* else -> note that No_Difference will Register the
* file already for us, using the new tag/date. This
* is the desired behaviour
*/
ret = T_UPTODATE;
}
}
}
}
else
{
/* The RCS file is a newer version than the user file */
if (vers->ts_user == NULL)
{
/* There is no user file, so just get it */
if (strcmp (command_name, "update") == 0)
if (!really_quiet)
error (0, 0, "warning: %s was lost", file);
ret = T_CHECKOUT;
}
else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
{
/*
* The user file is still unmodified, so just get it as well
*/
ret = T_CHECKOUT;
}
else
{
if (No_Difference (file, vers, entries))
/* really modified, needs to merge */
ret = T_NEEDS_MERGE;
else
/* not really modified, check it out */
ret = T_CHECKOUT;
}
}
}
/* free up the vers struct, or just return it */
if (versp != (Vers_TS **) NULL)
*versp = vers;
else
freevers_ts (&vers);
/* return the status of the file */
return (ret);
}
static void
sticky_ck (file, aflag, vers, entries)
char *file;
int aflag;
Vers_TS *vers;
List *entries;
{
if (aflag || vers->tag || vers->date)
{
char *enttag = vers->entdata->tag;
char *entdate = vers->entdata->date;
if ((enttag && vers->tag && strcmp (enttag, vers->tag)) ||
((enttag && !vers->tag) || (!enttag && vers->tag)) ||
(entdate && vers->date && strcmp (entdate, vers->date)) ||
((entdate && !vers->date) || (!entdate && vers->date)))
{
Register (entries, file, vers->vn_user, vers->ts_rcs,
vers->options, vers->tag, vers->date);
}
}
}

1229
gnu/usr.bin/cvs/cvs/commit.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,217 @@
/* @(#)config.h 1.19 92/03/31 */
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* This file holds (most of) the configuration tweaks that can be made to
* customize CVS for your site. CVS comes configured for a typical SunOS 4.x
* environment. The comments for each configurable item are intended to be
* self-explanatory. All #defines are tested first to see if an over-riding
* option was specified on the "make" command line.
*
* If special libraries are needed, you will have to edit the Makefile.in file
* or the configure script directly. Sorry.
*/
/*
* CVS provides the most features when used in conjunction with the Version-5
* release of RCS. Thus, it is the default. This also assumes that GNU diff
* Version-1.15 is being used as well -- you will have to configure your RCS
* V5 release separately to make this the case. If you do not have RCS V5 and
* GNU diff V1.15, comment out this define. You should not try mixing and
* matching other combinations of these tools.
*/
#ifndef HAVE_RCS5
#define HAVE_RCS5
#endif
/*
* If, before installing this version of CVS, you were running RCS V4 AND you
* are installing this CVS and RCS V5 and GNU diff 1.15 all at the same time,
* you should turn on the following define. It only exists to try to do
* reasonable things with your existing checked out files when you upgrade to
* RCS V5, since the keyword expansion formats have changed with RCS V5.
*
* If you already have been running with RCS5, or haven't been running with CVS
* yet at all, or are sticking with RCS V4 for now, leave the commented out.
*/
#ifndef HAD_RCS4
/* #define HAD_RCS4 */
#endif
/*
* For portability and heterogeneity reasons, CVS is shipped by default using
* my own text-file version of the ndbm database library in the src/myndbm.c
* file. If you want better performance and are not concerned about
* heterogeneous hosts accessing your modules file, turn this option off.
*/
#ifndef MY_NDBM
#define MY_NDBM
#endif
/*
* The "diff" program to execute when creating patch output. This "diff"
* must support the "-c" option for context diffing. Specify a full pathname
* if your site wants to use a particular diff. If you are using the GNU
* version of diff (version 1.15 or later), this should be "diff -a".
*
* NOTE: this program is only used for the ``patch'' sub-command. The other
* commands use rcsdiff which will use whatever version of diff was specified
* when rcsdiff was built on your system.
*/
#ifndef DIFF
#define DIFF "diff"
#endif
/*
* The "grep" program to execute when checking to see if a merged file had
* any conflicts. This "grep" must support the "-s" option and a standard
* regular expression as an argument. Specify a full pathname if your site
* wants to use a particular grep.
*/
#ifndef GREP
#define GREP "grep"
#endif
/*
* The "rm" program to execute when pruning directories that are not part of
* a release. This "rm" must support the "-fr" options. Specify a full
* pathname if your site wants to use a particular rm.
*/
#ifndef RM
#define RM "rm"
#endif
/*
* The "sort" program to execute when displaying the module database. Specify
* a full pathname if your site wants to use a particular sort.
*/
#ifndef SORT
#define SORT "sort"
#endif
/*
* By default, RCS programs are executed with the shell or through execlp(),
* so the user's PATH environment variable is searched. If you'd like to
* bind all RCS programs to a certain directory (perhaps one not in most
* people's PATH) then set the default in RCSBIN_DFLT. Note that setting
* this here will cause all RCS programs to be executed from this directory,
* unless the user overrides the default with the RCSBIN environment variable
* or the "-b" option to CVS.
*
* This define should be either the empty string ("") or a full pathname to the
* directory containing all the installed programs from the RCS distribution.
*/
#ifndef RCSBIN_DFLT
#define RCSBIN_DFLT ""
#endif
/*
* The default editor to use, if one does not specify the "-e" option to cvs,
* or does not have an EDITOR environment variable. I set this to just "vi",
* and use the shell to find where "vi" actually is. This allows sites with
* /usr/bin/vi or /usr/ucb/vi to work equally well (assuming that your PATH
* is reasonable).
*/
#ifndef EDITOR_DFLT
#define EDITOR_DFLT "vi"
#endif
/*
* The Repository file holds the path to the directory within the source
* repository that contains the RCS ,v files for each CVS working directory.
* This path is either a full-path or a path relative to CVSROOT.
*
* The only advantage that I can see to having a relative path is that One can
* change the physical location of the master source repository, change one's
* CVSROOT environment variable, and CVS will work without problems. I
* recommend using full-paths.
*/
#ifndef RELATIVE_REPOS
/* #define RELATIVE_REPOS */
#endif
/*
* When committing or importing files, you must enter a log message.
* Normally, you can do this either via the -m flag on the command line or an
* editor will be started for you. If you like to use logging templates (the
* rcsinfo file within the $CVSROOT/CVSROOT directory), you might want to
* force people to use the editor even if they specify a message with -m.
* Enabling FORCE_USE_EDITOR will cause the -m message to be appended to the
* temp file when the editor is started.
*/
#ifndef FORCE_USE_EDITOR
/* #define FORCE_USE_EDITOR */
#endif
/*
* When locking the repository, some sites like to remove locks and assume
* the program that created them went away if the lock has existed for a long
* time. This used to be the default for previous versions of CVS. CVS now
* attempts to be much more robust, so lock files should not be left around
* by mistake. The new behaviour will never remove old locks (they must now
* be removed by hand). Enabling CVS_FUDGELOCKS will cause CVS to remove
* locks that are older than CVSLCKAGE seconds.
* Use of this option is NOT recommended.
*/
#ifndef CVS_FUDGELOCKS
/* #define CVS_FUDGELOCKS */
#endif
/*
* When committing a permanent change, CVS and RCS make a log entry of
* who committed the change. If you are committing the change logged in
* as "root" (not under "su" or other root-priv giving program), CVS/RCS
* cannot determine who is actually making the change.
*
* As such, by default, CVS disallows changes to be committed by users
* logged in as "root". You can disable this option by commenting
* out the lines below.
*/
#ifndef CVS_BADROOT
#define CVS_BADROOT
#endif
/*
* The "cvs diff" command accepts all the single-character options that GNU
* diff (1.15) accepts. Except -D. GNU diff uses -D as a way to put
* cpp-style #define's around the output differences. CVS, by default, uses
* -D to specify a free-form date (like "cvs diff -D '1 week ago'"). If
* you would prefer that the -D option of "cvs diff" work like the GNU diff
* option, then comment out this define.
*/
#ifndef CVS_DIFFDATE
#define CVS_DIFFDATE
#endif
/* End of CVS configuration section */
/*
* Externs that are included in libc, but are used frequently enough to
* warrant defining here.
*/
#ifndef STDC_HEADERS
extern void exit ();
#endif
#ifndef getwd
extern char *getwd ();
#endif
/*
* Some UNIX distributions don't include these in their stat.h Defined here
* because "config.h" is always included last.
*/
#ifndef S_IWRITE
#define S_IWRITE 0000200 /* write permission, owner */
#endif
#ifndef S_IWGRP
#define S_IWGRP 0000020 /* write permission, grougroup */
#endif
#ifndef S_IWOTH
#define S_IWOTH 0000002 /* write permission, other */
#endif

View File

@ -0,0 +1,100 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* Create Administration.
*
* Creates a CVS administration directory based on the argument repository; the
* "Entries" file is prefilled from the "initrecord" argument.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)create_adm.c 1.24 92/03/31";
#endif
void
Create_Admin (dir, repository, tag, date)
char *dir;
char *repository;
char *tag;
char *date;
{
FILE *fout;
char *cp;
char tmp[PATH_MAX];
if (noexec)
return;
if (!isdir (repository))
error (1, 0, "there is no repository %s", repository);
if (dir != NULL)
(void) sprintf (tmp, "%s/%s", dir, CVSADM);
else
(void) strcpy (tmp, CVSADM);
if (isfile (tmp))
error (1, 0, "there is a version here already");
else
{
if (dir != NULL)
(void) sprintf (tmp, "%s/%s", dir, OCVSADM);
else
(void) strcpy (tmp, OCVSADM);
if (isfile (tmp))
error (1, 0, "there is a version here already");
}
if (dir != NULL)
(void) sprintf (tmp, "%s/%s", dir, CVSADM);
else
(void) strcpy (tmp, CVSADM);
make_directory (tmp);
if (dir != NULL)
(void) sprintf (tmp, "%s/%s", dir, CVSADM_REP);
else
(void) strcpy (tmp, CVSADM_REP);
fout = open_file (tmp, "w+");
cp = repository;
strip_path (cp);
#ifdef RELATIVE_REPOS
/*
* If the Repository file is to hold a relative path, try to strip off
* the leading CVSroot argument.
*/
if (CVSroot != NULL)
{
char path[PATH_MAX];
(void) sprintf (path, "%s/", CVSroot);
if (strncmp (repository, path, strlen (path)) == 0)
cp = repository + strlen (path);
}
#endif
if (fprintf (fout, "%s\n", cp) == EOF)
error (1, errno, "write to %s failed", tmp);
if (fclose (fout) == EOF)
error (1, errno, "cannot close %s", tmp);
/* now, do the Entries file */
if (dir != NULL)
(void) sprintf (tmp, "%s/%s", dir, CVSADM_ENT);
else
(void) strcpy (tmp, CVSADM_ENT);
fout = open_file (tmp, "w+");
if (fclose (fout) == EOF)
error (1, errno, "cannot close %s", tmp);
/* Create a new CVS/Tag file */
WriteTag (dir, tag, date);
}

1991
gnu/usr.bin/cvs/cvs/cvs.1 Normal file

File diff suppressed because it is too large Load Diff

326
gnu/usr.bin/cvs/cvs/cvs.5 Normal file
View File

@ -0,0 +1,326 @@
.TH cvs 5 "12 February 1992"
.\" Full space in nroff; half space in troff
.de SP
.if n .sp
.if t .sp .5
..
.SH NAME
cvs \- Concurrent Versions System support files
.SH SYNOPSIS
.hy 0
.na
.TP
.B $CVSROOT/CVSROOT/modules,v
.TP
.B $CVSROOT/CVSROOT/commitinfo,v
.TP
.B $CVSROOT/CVSROOT/loginfo,v
.TP
.B $CVSROOT/CVSROOT/rcsinfo,v
.TP
.B $CVSROOT/CVSROOT/editinfo,v
.TP
.B $CVSROOT/CVSROOT/cvsignore,v
.TP
.B $CVSROOT/CVSROOT/history
.ad b
.hy 1
.SH DESCRIPTION
.B cvs
is a system for providing source control to hierarchical collections
of source directories. Commands and procedures for using \fBcvs\fP
are described in
.BR cvs ( 1 ).
.SP
.B cvs
manages \fIsource repositories\fP, the directories containing master
copies of the revision-controlled files, by copying particular
revisions of the files to (and modifications back from) developers'
private \fIworking directories\fP. In terms of file structure, each
individual source repository is an immediate subdirectory of
\fB$CVSROOT\fP.
.SP
The files described here are supporting files; they do not have to
exist for \fBcvs\fP to operate, but they allow you to make \fBcvs\fP
operation more flexible.
.SP
The
.BR cvsinit ( 1 )
shell script included at the top-level of the
.B cvs
distribution can be used to setup an initial
.B $CVSROOT/CVSROOT
area, if you don't have one already.
.SP
You can use the `\|modules\|' file to define symbolic names for
collections of source maintained with \fBcvs\fP. If there is no
`\|modules\|' file, developers must specify complete path names
(absolute, or relative to \fB$CVSROOT\fP) for the files they wish to
manage with \fBcvs\fP commands.
.SP
You can use the `\|commitinfo\|' file to define programs to execute
whenever `\|\fBcvs commit\fP\|' is about to execute.
These programs are used for ``pre-commit'' checking to verify that the
modified, added, and removed files are really ready to be committed.
Some uses for this check might be to turn off a portion (or all) of the
source repository from a particular person or group.
Or, perhaps, to verify that the changed files conform to the site's
standards for coding practice.
.SP
You can use the `\|loginfo\|' file to define programs to execute after
any
.BR commit ,
which writes a log entry for changes in the repository.
These logging programs might be used to append the log message to a file.
Or send the log message through electronic mail to a group of developers.
Or, perhaps, post the log message to a particular newsgroup.
.SP
You can use the `\|rcsinfo\|' file to define forms for log messages.
.SP
You can use the `\|editinfo\|' file to define a program to execute for
editing/validating `\|\fBcvs commit\fP\|' log entries.
This is most useful when used with a `\|rcsinfo\|' forms specification, as
it can verify that the proper fields of the form have been filled in by the
user committing the change.
.SP
You can use the `\|cvsignore\|' file to specify the default list of
files to ignore during \fBupdate\fP.
.SP
You can use the `\|history\|' file to record the \fBcvs\fP commands
that affect the repository.
The creation of this file enables history logging.
.SH FILES
.TP
.B modules
The `\|modules\|' file records your definitions of names for
collections of source code. \fBcvs\fP will use these definitions if
you create a file with the right format in
`\|\fB$CVSROOT/CVSROOT/modules,v\fP\|'.
The
.BR mkmodules ( 1 )
command should be run whenever the modules file changes, so that the
appropriate files can be generated (depending on how you have configured
.B cvs
operation).
.SP
To allow convenient editing of the `\|modules\|' file itself, the file should
include an entry like the following (where \fIlocalbin\fP represents the
directory where your site installs programs like
.BR mkmodules ( 1 )):
.SP
.nf
\&\fBmodules \-i /\fP\fIlocalbin\fP\fB/mkmodules CVSROOT modules\fP
.fi
.SP
This defines the name `\|\fBmodules\fP\|' as the module name for the
file itself, so that you can use
.SP
.in +1i
.ft B
.nf
example% cvs checkout modules
.fi
.ft P
.in -1i
.SP
to get an editable copy of the file. You should define similar module
entries for the other configuration files described here (except
\&`\|history\|').
The
.BR cvsinit ( 1 )
script will setup a smilar `\|modules\|' file for you automatically.
.SP
The `\|modules\|' file may contain blank lines and comments (lines
beginning with `\|\fB#\fP\|') as well as module definitions.
Long lines can be continued on the next line by specifying a backslash
(``\e'') as the last character on the line.
.SP
A \fImodule definition\fP is a single line of the `\|modules\|' file,
in either of two formats. In both cases, \fImname\fP represents the
symbolic module name, and the remainder of the line is its definition.
.SP
\fImname\fP \fB\-a\fP \fIaliases\fP\|.\|.\|.
.br
This represents the simplest way of defining a module \fImname\fP.
The `\|\fB\-a\fP\|' flags the definition as a simple alias: \fBcvs\fP
will treat any use of \fImname\fP (as a command argument) as if the list
of names \fIaliases\fP had been specified instead. \fIaliases\fP may
contain either other module names or paths. When you use paths in
\fIaliases\fP, `\|\fBcvs checkout\fP\|' creates all intermediate
directories in the working directory, just as if the path had been
specified explicitly in the \fBcvs\fP arguments.
.SP
.nf
\fImname\fP [ \fIoptions\fP ] \fIdir\fP [ \fIfiles\fP\|.\|.\|. ] [ \fB&\fP\fImodule\fP\|.\|.\|. ]
.fi
.SP
In the simplest case, this form of module definition reduces to
`\|\fImname dir\fP\|'. This defines all the files in directory
\fIdir\fP as module \fImname\fP. \fIdir\fP is a relative path (from
\fB$CVSROOT\fP) to a directory of source in one of the source
repositories. In this case, on \fBcheckout\fP, a single directory
called \fImname\fP is created as a working directory; no intermediate
directory levels are used by default, even if \fIdir\fP was a path
involving several directory levels.
.SP
By explicitly specifying \fIfiles\fP in the module definition after
\fIdir\fP, you can select particular files from directory
\fIdir\fP. The sample definition for \fBmodules\fP is an example of
a module defined with a single file from a particular directory. Here
is another example:
.SP
.nf
.ft B
m4test unsupported/gnu/m4 foreach.m4 forloop.m4
.ft P
.fi
.SP
With this definition, executing `\|\fBcvs checkout m4test\fP\|'
will create a single working directory `\|m4test\|' containing the two
files listed, which both come from a common directory several levels
deep in the \fBcvs\fP source repository.
.SP
A module definition can refer to other modules by including
`\|\fB&\fP\fImodule\fP\|' in its definition. \fBcheckout\fP creates
a subdirectory for each such \fImodule\fP, in your working directory.
.br
.I
New in \fBcvs\fP 1.3;
avoid this feature if sharing module definitions with older versions
of \fBcvs\fP.
.SP
Finally, you can use one or more of the following \fIoptions\fP in
module definitions:
.SP
\&`\|\fB\-d\fP \fIname\fP\|', to name the working directory something
other than the module name.
.br
.I
New in \fBcvs\fP 1.3;
avoid this feature if sharing module definitions with older versions
of \fBcvs\fP.
.SP
\&`\|\fB\-i\fP \fIprog\fP\|' allows you to specify a program \fIprog\fP
to run whenever files in a module are committed. \fIprog\fP runs with a
single argument, the full pathname of the affected directory in a
source repository. The `\|commitinfo\|', `\|loginfo\|', and
`\|editinfo\|' files provide other ways to call a program on \fBcommit\fP.
.SP
`\|\fB\-o\fP \fIprog\fP\|' allows you to specify a program \fIprog\fP
to run whenever files in a module are checked out. \fIprog\fP runs
with a single argument, the module name.
.SP
`\|\fB\-t\fP \fIprog\fP\|' allows you to specify a program \fIprog\fP
to run whenever files in a module are tagged. \fIprog\fP runs with two
arguments: the module name and the symbolic tag specified to \fBrtag\fP.
.SP
`\|\fB\-u\fP \fIprog\fP\|' allows you to specify a program \fIprog\fP
to run whenever `\|\fBcvs update\fP\|' is executed from the top-level
directory of the checked-out module. \fIprog\fP runs with a
single argument, the full path to the source repository for this module.
.TP
\&\fBcommitinfo\fP, \fBloginfo\fP, \fBrcsinfo\fP, \fBeditinfo\fP
These files all specify programs to call at different points in the
`\|\fBcvs commit\fP\|' process. They have a common structure.
Each line is a pair of fields: a regular expression, separated by
whitespace from a filename or command-line template.
Whenever one of the regular expression matches a directory name in the
repository, the rest of the line is used.
If the line begins with a \fB#\fP character, the entire line is considered
a comment and is ignored.
Whitespace between the fields is also ignored.
.SP
For `\|loginfo\|', the rest of the
line is a command-line template to execute.
The templates can include not only
a program name, but whatever list of arguments you wish. If you write
`\|\fB%s\fP\|' somewhere on the argument list, \fBcvs\fP supplies, at
that point, the list of files affected by the \fBcommit\fP.
The first entry in the list is the relative path within the source
repository where the change is being made.
The remaining arguments list the files that are being modified, added, or
removed by this \fBcommit\fP invocation.
.SP
For `\|commitinfo\|', the rest of the line is a command-line template to
execute.
The template can include can include not only a program name, but whatever
list of arguments you wish.
The full path to the current source repository is appended to the template,
followed by the file names of any files involved in the commit (added,
removed, and modified files).
.SP
For `\|rcsinfo\|', the rest of the line is the full path to a file that
should be loaded into the log message template.
.SP
For `\|editinfo\|', the rest of the line is a command-line template to
execute.
The template can include can include not only a program name, but whatever
list of arguments you wish.
The full path to the current log message template file is appended to the
template.
.SP
You can use one of two special strings instead of a regular
expression: `\|\fBALL\fP\|' specifies a command line template that
must always be executed, and `\|\fBDEFAULT\fP\|' specifies a command
line template to use if no regular expression is a match.
.SP
The `\|commitinfo\|' file contains commands to execute \fIbefore\fP any
other \fBcommit\fP activity, to allow you to check any conditions that
must be satisfied before \fBcommit\fP can proceed. The rest of the
\fBcommit\fP will execute only if all selected commands from this file
exit with exit status \fB0\fP.
.SP
The `\|rcsinfo\|' file allows you to specify \fIlog templates\fP for
the \fBcommit\fP logging session; you can use this to provide a form
to edit when filling out the \fBcommit\fP log. The field after the
regular expression, in this file, contains filenames (of files
containing the logging forms) rather than command templates.
.SP
The `\|editinfo\|' file allows you to execute a script \fIbefore the
commit starts\fP, but after the log information is recorded. These
"edit" scripts can verify information recorded in the log file. If
the edit script exits wth a non-zero exit status, the commit is aborted.
.SP
The `\|loginfo\|' file contains commands to execute \fIat the end\fP
of a commit. The text specified as a commit log message is piped
through the command; typical uses include sending mail, filing an
article in a newsgroup, or appending to a central file.
.TP
\&\fBcvsignore\fP, \fB.cvsignore\fP
The default list of files (or
.BR sh ( 1 )
file name patterns) to ignore during `\|\fBcvs update\fP\|'.
At startup time, \fBcvs\fP loads the compiled in default list of file name
patterns (see
.BR cvs ( 1 )).
Then the per-repository list included in \fB$CVSROOT/CVSROOT/cvsignore\fP
is loaded, if it exists.
Then the per-user list is loaded from `\|$HOME/.cvsignore\|'.
Finally, as \fBcvs\fP traverses through your directories, it will load any
per-directory `\|.cvsignore\|' files whenever it finds one.
These per-directory files are only valid for exactly the directory that
contains them, not for any sub-directories.
.TP
.B history
Create this file in \fB$CVSROOT/CVSROOT\fP to enable history logging
(see the description of `\|\fBcvs history\fP\|').
.SH "SEE ALSO"
.BR cvs ( 1 ),
.BR mkmodules ( 1 ).
.SH COPYING
Copyright \(co 1992 Cygnus Support, Brian Berliner, and Jeff Polk
.PP
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
.PP
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided that the
entire resulting derived work is distributed under the terms of a
permission notice identical to this one.
.PP
Permission is granted to copy and distribute translations of this
manual into another language, under the above conditions for modified
versions, except that this permission notice may be included in
translations approved by the Free Software Foundation instead of in
the original English.

438
gnu/usr.bin/cvs/cvs/cvs.h Normal file
View File

@ -0,0 +1,438 @@
/* @(#)cvs.h 1.72 92/03/31 */
#include "system.h"
#include <stdio.h>
#include <ctype.h>
#include <pwd.h>
#include <signal.h>
#include "hash.h"
#include "rcs.h"
#include "regex.h"
#include "fnmatch.h"
#include "getopt.h"
#include "wait.h"
#include "config.h"
#ifdef MY_NDBM
#include "myndbm.h"
#else
#include <ndbm.h>
#endif /* !MY_NDBM */
/* XXX - for now this is static */
#undef PATH_MAX
#ifdef MAXPATHLEN
#define PATH_MAX MAXPATHLEN+2
#else
#define PATH_MAX 1024+2
#endif
/* just in case this implementation does not define this */
#ifndef L_tmpnam
#define L_tmpnam 50
#endif
#if __STDC__
#define CONST const
#define PTR void *
#else
#define CONST
#define PTR char *
#endif
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* Definitions for the CVS Administrative directory and the files it contains.
* Here as #define's to make changing the names a simple task.
*/
#define CVSADM "CVS"
#define CVSADM_ENT "CVS/Entries"
#define CVSADM_ENTBAK "CVS/Entries.Backup"
#define CVSADM_ENTSTAT "CVS/Entries.Static"
#define CVSADM_REP "CVS/Repository"
#define CVSADM_CIPROG "CVS/Checkin.prog"
#define CVSADM_UPROG "CVS/Update.prog"
#define CVSADM_TAG "CVS/Tag"
/*
* The following are obsolete and are maintained here only so that they can be
* cleaned up during the transition
*/
#define OCVSADM "CVS.adm" /* for CVS 1.2 and earlier */
#define CVSADM_FILE "CVS/Files"
#define CVSADM_MOD "CVS/Mod"
/*
* Definitions for the CVSROOT Administrative directory and the files it
* contains. This directory is created as a sub-directory of the $CVSROOT
* environment variable, and holds global administration information for the
* entire source repository beginning at $CVSROOT.
*/
#define CVSROOTADM "CVSROOT"
#define CVSROOTADM_MODULES "modules"
#define CVSROOTADM_LOGINFO "loginfo"
#define CVSROOTADM_RCSINFO "rcsinfo"
#define CVSROOTADM_COMMITINFO "commitinfo"
#define CVSROOTADM_EDITINFO "editinfo"
#define CVSROOTADM_HISTORY "history"
#define CVSROOTADM_IGNORE "cvsignore"
#define CVSNULLREPOS "Emptydir" /* an empty directory */
/* support for the modules file (CVSROOTADM_MODULES) */
#define CVSMODULE_OPTS "ad:i:lo:s:t:u:"/* options in modules file */
#define CVSMODULE_SPEC '&' /* special delimiter */
/*
* The following are obsolete and are maintained here only so that they can be
* cleaned up during the transition
*/
#define OCVSROOTADM "CVSROOT.adm" /* for CVS 1.2 and earlier */
/* Other CVS file names */
#define CVSATTIC "Attic"
#define CVSLCK "#cvs.lock"
#define CVSTFL "#cvs.tfl"
#define CVSRFL "#cvs.rfl"
#define CVSWFL "#cvs.wfl"
#define CVSEXT_OPT ",p"
#define CVSEXT_LOG ",t"
#define CVSPREFIX ",,"
#define CVSDOTIGNORE ".cvsignore"
/* miscellaneous CVS defines */
#define CVSEDITPREFIX "CVS: "
#define CVSLCKAGE (60*60) /* 1-hour old lock files cleaned up */
#define CVSLCKSLEEP 30 /* wait 30 seconds before retrying */
#define CVSBRANCH "1.1.1" /* RCS branch used for vendor srcs */
#define BAKPREFIX ".#" /* when rcsmerge'ing */
#define DEVNULL "/dev/null"
#define FALSE 0
#define TRUE 1
/*
* Special tags. -rHEAD refers to the head of an RCS file, regardless of any
* sticky tags. -rBASE refers to the current revision the user has checked
* out This mimics the behaviour of RCS.
*/
#define TAG_HEAD "HEAD"
#define TAG_BASE "BASE"
/* Environment variable used by CVS */
#define CVSREAD_ENV "CVSREAD" /* make files read-only */
#define CVSREAD_DFLT FALSE /* writable files by default */
#define RCSBIN_ENV "RCSBIN" /* RCS binary directory */
/* #define RCSBIN_DFLT Set by config.h */
#define EDITOR_ENV "EDITOR" /* which editor to use */
/* #define EDITOR_DFLT Set by config.h */
#define CVSROOT_ENV "CVSROOT" /* source directory root */
#define CVSROOT_DFLT NULL /* No dflt; must set for checkout */
#define IGNORE_ENV "CVSIGNORE" /* More files to ignore */
/*
* If the beginning of the Repository matches the following string, strip it
* so that the output to the logfile does not contain a full pathname.
*
* If the CVSROOT environment variable is set, it overrides this define.
*/
#define REPOS_STRIP "/master/"
/*
* The maximum number of files per each CVS directory. This is mainly for
* sizing arrays statically rather than dynamically. 3000 seems plenty for
* now.
*/
#define MAXFILEPERDIR 3000
#define MAXLINELEN 5000 /* max input line from a file */
#define MAXPROGLEN 30000 /* max program length to system() */
#define MAXLISTLEN 40000 /* For [A-Z]list holders */
#define MAXMESGLEN 10000 /* max RCS log message size */
#define MAXDATELEN 50 /* max length for a date */
/* The type of request that is being done in do_module() */
enum mtype
{
CHECKOUT, TAG, PATCH
};
/*
* defines for Classify_File() to determine the current state of a file.
* These are also used as types in the data field for the list we make for
* Update_Logfile in commit, import, and add.
*/
enum classify_type
{
T_UNKNOWN = 1, /* no old-style analog existed */
T_CONFLICT, /* C (conflict) list */
T_NEEDS_MERGE, /* G (needs merging) list */
T_MODIFIED, /* M (needs checked in) list */
T_CHECKOUT, /* O (needs checkout) list */
T_ADDED, /* A (added file) list */
T_REMOVED, /* R (removed file) list */
T_REMOVE_ENTRY, /* W (removed entry) list */
T_UPTODATE, /* File is up-to-date */
T_TITLE /* title for node type */
};
typedef enum classify_type Ctype;
/*
* a struct vers_ts contains all the information about a file including the
* user and rcs file names, and the version checked out and the head.
*
* this is usually obtained from a call to Version_TS which takes a tag argument
* for the RCS file if desired
*/
struct vers_ts
{
char *vn_user; /* rcs version user file derives from
* it can have the following special
* values:
* empty = no user file
* 0 = user file is new
* -vers = user file to be removed */
char *vn_rcs; /* the verion for the rcs file
* (tag version?) */
char *ts_user; /* the timestamp for the user file */
char *ts_rcs; /* the user timestamp from entries */
char *options; /* opts from Entries file
* (keyword expansion) */
char *tag; /* tag stored in the Entries file */
char *date; /* date stored in the Entries file */
Entnode *entdata; /* pointer to entries file node */
RCSNode *srcfile; /* pointer to parsed src file info */
};
typedef struct vers_ts Vers_TS;
/*
* structure used for list-private storage by ParseEntries() and
* Version_TS().
*/
struct stickydirtag
{
int aflag;
char *tag;
char *date;
char *options;
};
/* flags for run_exec(), the fast system() for CVS */
#define RUN_NORMAL 0x0000 /* no special behaviour */
#define RUN_COMBINED 0x0001 /* stdout is duped to stderr */
#define RUN_REALLY 0x0002 /* do the exec, even if noexec is on */
#define RUN_STDOUT_APPEND 0x0004 /* append to stdout, don't truncate */
#define RUN_STDERR_APPEND 0x0008 /* append to stderr, don't truncate */
#define RUN_SIGIGNORE 0x0010 /* ignore interrupts for command */
#define RUN_TTY (char *)0 /* for the benefit of lint */
/* Flags for find_{names,dirs} routines */
#define W_LOCAL 0x01 /* look for files locally */
#define W_REPOS 0x02 /* look for files in the repository */
#define W_ATTIC 0x04 /* look for files in the attic */
/* Flags for return values of direnter procs for the recursion processor */
enum direnter_type
{
R_PROCESS = 1, /* process files and maybe dirs */
R_SKIP_FILES, /* don't process files in this dir */
R_SKIP_DIRS, /* don't process sub-dirs */
R_SKIP_ALL /* don't process files or dirs */
};
typedef enum direnter_type Dtype;
extern char *program_name, *command_name;
extern char *Rcsbin, *Editor, *CVSroot;
extern char *CurDir;
extern int really_quiet, quiet;
extern int use_editor;
extern int cvswrite;
extern int trace; /* Show all commands */
extern int noexec; /* Don't modify disk anywhere */
extern int logoff; /* Don't write history entry */
/* Externs that are included directly in the CVS sources */
#if __STDC__
int Reader_Lock (char *xrepository);
DBM *open_module (void);
FILE *Fopen (char *name, char *mode);
FILE *open_file (char *name, char *mode);
List *Find_Dirs (char *repository, int which);
List *ParseEntries (int aflag);
char *Make_Date (char *rawdate);
char *Name_Repository (char *dir, char *update_dir);
char *Short_Repository (char *repository);
char *getcaller (void);
char *time_stamp (char *file);
char *xmalloc (int bytes);
char *xrealloc (char *ptr, int bytes);
char *xstrdup (char *str);
int No_Difference (char *file, Vers_TS * vers, List * entries);
int Parse_Info (char *infofile, char *repository, int (*callproc) (), int all);
int Reader_Lock (char *xrepository);
int SIG_register (int sig, SIGTYPE (*fn) ());
int Writer_Lock (List * list);
int gethostname (char *name, int namelen);
int ign_name (char *name);
int isdir (char *file);
int isfile (char *file);
int islink (char *file);
int isreadable (char *file);
int iswritable (char *file);
int link_file (char *from, char *to);
int numdots (char *s);
int run_exec (char *stin, char *stout, char *sterr, int flags);
int unlink_file (char *f);
int update (int argc, char *argv[]);
int xcmp (char *file1, char *file2);
int yesno (void);
time_t get_date (char *date, struct timeb *now);
void Create_Admin (char *dir, char *repository, char *tag, char *date);
void Lock_Cleanup (void);
void ParseTag (char **tagp, char **datep);
void Scratch_Entry (List * list, char *fname);
void WriteTag (char *dir, char *tag, char *date);
void cat_module (int status);
void check_entries (char *dir);
void close_module (DBM * db);
void copy_file (char *from, char *to);
void error (int status, int errnum, char *message,...);
void fperror (FILE * fp, int status, int errnum, char *message,...);
void free_names (int *pargc, char *argv[]);
void freevers_ts (Vers_TS ** versp);
void ign_add (char *ign, int hold);
void ign_add_file (char *file, int hold);
void ign_setup (void);
void line2argv (int *pargc, char *argv[], char *line);
void make_directories (char *name);
void make_directory (char *name);
void rename_file (char *from, char *to);
void run_arg (char *s);
void run_args (char *fmt,...);
void run_print (FILE * fp);
void run_setup (char *fmt,...);
void strip_path (char *path);
void update_delproc (Node * p);
void usage (char **cpp);
void xchmod (char *fname, int writable);
int Checkin (int type, char *file, char *repository, char *rcs, char *rev,
char *tag, char *message, List * entries);
Ctype Classify_File (char *file, char *tag, char *date, char *options,
int force_tag_match, int aflag, char *repository,
List *entries, List *srcfiles, Vers_TS **versp);
List *Find_Names (char *repository, int which, int aflag,
List ** optentries);
void Register (List * list, char *fname, char *vn, char *ts,
char *options, char *tag, char *date);
void Update_Logfile (char *repository, char *xmessage, char *xrevision,
FILE * xlogfp, List * xchanges);
Vers_TS *Version_TS (char *repository, char *options, char *tag,
char *date, char *user, int force_tag_match,
int set_time, List * entries, List * xfiles);
void do_editor (char *dir, char *message, char *repository,
List * changes);
int do_module (DBM * db, char *mname, enum mtype m_type, char *msg,
int (*callback_proc) (), char *where, int shorten,
int local_specified, int run_module_prog, char *extra_arg);
int do_recursion (int (*xfileproc) (), int (*xfilesdoneproc) (),
Dtype (*xdirentproc) (), int (*xdirleaveproc) (),
Dtype xflags, int xwhich, int xaflag, int xreadlock,
int xdosrcs);
int do_update (int argc, char *argv[], char *xoptions, char *xtag,
char *xdate, int xforce, int local, int xbuild,
int xaflag, int xprune, int xpipeout, int which,
char *xjoin_rev1, char *xjoin_rev2, char *preload_update_dir);
void history_write (int type, char *update_dir, char *revs, char *name,
char *repository);
int start_recursion (int (*fileproc) (), int (*filesdoneproc) (),
Dtype (*direntproc) (), int (*dirleaveproc) (),
int argc, char *argv[], int local, int which,
int aflag, int readlock, char *update_preload,
int dosrcs);
void SIG_beginCrSect ();
void SIG_endCrSect ();
#else /* !__STDC__ */
DBM *open_module ();
FILE *Fopen ();
FILE *open_file ();
List *Find_Dirs ();
List *Find_Names ();
List *ParseEntries ();
Vers_TS *Version_TS ();
char *Make_Date ();
char *Name_Repository ();
char *Short_Repository ();
char *getcaller ();
char *time_stamp ();
char *xmalloc ();
char *xrealloc ();
char *xstrdup ();
int Checkin ();
Ctype Classify_File ();
int No_Difference ();
int Parse_Info ();
int Reader_Lock ();
int SIG_register ();
int Writer_Lock ();
int do_module ();
int do_recursion ();
int do_update ();
int gethostname ();
int ign_name ();
int isdir ();
int isfile ();
int islink ();
int isreadable ();
int iswritable ();
int link_file ();
int numdots ();
int run_exec ();
int start_recursion ();
int unlink_file ();
int update ();
int xcmp ();
int yesno ();
time_t get_date ();
void Create_Admin ();
void Lock_Cleanup ();
void ParseTag ();
void ParseTag ();
void Register ();
void Scratch_Entry ();
void Update_Logfile ();
void WriteTag ();
void cat_module ();
void check_entries ();
void close_module ();
void copy_file ();
void do_editor ();
void error ();
void fperror ();
void free_names ();
void freevers_ts ();
void history_write ();
void ign_add ();
void ign_add_file ();
void ign_setup ();
void line2argv ();
void make_directories ();
void make_directory ();
void rename_file ();
void run_arg ();
void run_args ();
void run_print ();
void run_setup ();
void strip_path ();
void update_delproc ();
void usage ();
void xchmod ();
void SIG_beginCrSect ();
void SIG_endCrSect ();
#endif /* __STDC__ */

407
gnu/usr.bin/cvs/cvs/diff.c Normal file
View File

@ -0,0 +1,407 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* Difference
*
* Run diff against versions in the repository. Options that are specified are
* passed on directly to "rcsdiff".
*
* Without any file arguments, runs diff against all the currently modified
* files.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)diff.c 1.52 92/04/10";
#endif
#if __STDC__
static Dtype diff_dirproc (char *dir, char *pos_repos, char *update_dir);
static int diff_dirleaveproc (char *dir, int err, char *update_dir);
static int diff_file_nodiff (char *file, char *repository, List *entries,
List *srcfiles, Vers_TS *vers);
static int diff_fileproc (char *file, char *update_dir, char *repository,
List * entries, List * srcfiles);
static void diff_mark_errors (int err);
#else
static int diff_fileproc ();
static Dtype diff_dirproc ();
static int diff_dirleaveproc ();
static int diff_file_nodiff ();
static void diff_mark_errors ();
#endif /* __STDC__ */
static char *diff_rev1, *diff_rev2;
static char *diff_date1, *diff_date2;
static char *use_rev1, *use_rev2;
static char *options;
static char opts[PATH_MAX];
static int diff_errors;
static char *diff_usage[] =
{
"Usage: %s %s [-l] [rcsdiff-options]\n",
#ifdef CVS_DIFFDATE
" [[-r rev1 | -D date1] [-r rev2 | -D date2]] [files...] \n",
#else
" [-r rev1 [-r rev2]] [files...] \n",
#endif
"\t-l\tLocal directory only, not recursive\n",
"\t-D d1\tDiff revision for date against working file.\n",
"\t-D d2\tDiff rev1/date1 against date2.\n",
"\t-r rev1\tDiff revision for rev1 against working file.\n",
"\t-r rev2\tDiff rev1/date1 against rev2.\n",
NULL
};
int
diff (argc, argv)
int argc;
char *argv[];
{
char tmp[50];
int c, err = 0;
int local = 0;
if (argc == -1)
usage (diff_usage);
/*
* Note that we catch all the valid arguments here, so that we can
* intercept the -r arguments for doing revision diffs; and -l/-R for a
* non-recursive/recursive diff.
*/
optind = 1;
while ((c = gnu_getopt (argc, argv,
"abcdefhilnpqtuw0123456789BHQRTC:D:F:I:L:V:k:r:")) != -1)
{
switch (c)
{
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
case 'h': case 'i': case 'n': case 'p': case 't': case 'u':
case 'w': case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': case 'B':
case 'H': case 'T': case 'Q':
(void) sprintf (tmp, " -%c", (char) c);
(void) strcat (opts, tmp);
if (c == 'Q')
{
quiet = 1;
really_quiet = 1;
c = 'q';
}
break;
case 'C': case 'F': case 'I': case 'L': case 'V':
#ifndef CVS_DIFFDATE
case 'D':
#endif
(void) sprintf (tmp, " -%c%s", (char) c, optarg);
(void) strcat (opts, tmp);
break;
case 'R':
local = 0;
break;
case 'l':
local = 1;
break;
case 'q':
quiet = 1;
break;
case 'k':
if (options)
free (options);
options = RCS_check_kflag (optarg);
break;
case 'r':
if (diff_rev2 != NULL || diff_date2 != NULL)
error (1, 0,
"no more than two revisions/dates can be specified");
if (diff_rev1 != NULL || diff_date1 != NULL)
diff_rev2 = optarg;
else
diff_rev1 = optarg;
break;
#ifdef CVS_DIFFDATE
case 'D':
if (diff_rev2 != NULL || diff_date2 != NULL)
error (1, 0,
"no more than two revisions/dates can be specified");
if (diff_rev1 != NULL || diff_date1 != NULL)
diff_date2 = Make_Date (optarg);
else
diff_date1 = Make_Date (optarg);
break;
#endif
case '?':
default:
usage (diff_usage);
break;
}
}
argc -= optind;
argv += optind;
/* make sure options is non-null */
if (!options)
options = xstrdup ("");
/* start the recursion processor */
err = start_recursion (diff_fileproc, (int (*) ()) NULL, diff_dirproc,
diff_dirleaveproc, argc, argv, local,
W_LOCAL, 0, 1, (char *) NULL, 1);
/* clean up */
free (options);
return (err);
}
/*
* Do a file diff
*/
/* ARGSUSED */
static int
diff_fileproc (file, update_dir, repository, entries, srcfiles)
char *file;
char *update_dir;
char *repository;
List *entries;
List *srcfiles;
{
int status, err = 2; /* 2 == trouble, like rcsdiff */
Vers_TS *vers;
vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL,
file, 1, 0, entries, srcfiles);
if (vers->vn_user == NULL)
{
error (0, 0, "I know nothing about %s", file);
freevers_ts (&vers);
diff_mark_errors (err);
return (err);
}
else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
{
error (0, 0, "%s is a new entry, no comparison available", file);
freevers_ts (&vers);
diff_mark_errors (err);
return (err);
}
else if (vers->vn_user[0] == '-')
{
error (0, 0, "%s was removed, no comparison available", file);
freevers_ts (&vers);
diff_mark_errors (err);
return (err);
}
else
{
if (vers->vn_rcs == NULL && vers->srcfile == NULL)
{
error (0, 0, "cannot find revision control file for %s", file);
freevers_ts (&vers);
diff_mark_errors (err);
return (err);
}
else
{
if (vers->ts_user == NULL)
{
error (0, 0, "cannot find %s", file);
freevers_ts (&vers);
diff_mark_errors (err);
return (err);
}
}
}
if (diff_file_nodiff (file, repository, entries, srcfiles, vers))
{
freevers_ts (&vers);
return (0);
}
(void) fflush (stdout);
if (use_rev2)
{
run_setup ("%s%s %s %s -r%s -r%s", Rcsbin, RCS_DIFF,
opts, *options ? options : vers->options,
use_rev1, use_rev2);
}
else
{
run_setup ("%s%s %s %s -r%s", Rcsbin, RCS_DIFF, opts,
*options ? options : vers->options, use_rev1);
}
run_arg (vers->srcfile->path);
switch ((status = run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
RUN_REALLY|RUN_COMBINED)))
{
case -1: /* fork failed */
error (1, errno, "fork failed during rcsdiff of %s",
vers->srcfile->path);
case 0: /* everything ok */
err = 0;
break;
default: /* other error */
err = status;
break;
}
(void) fflush (stdout);
freevers_ts (&vers);
diff_mark_errors (err);
return (err);
}
/*
* Remember the exit status for each file.
*/
static void
diff_mark_errors (err)
int err;
{
if (err > diff_errors)
diff_errors = err;
}
/*
* Print a warm fuzzy message when we enter a dir
*/
/* ARGSUSED */
static Dtype
diff_dirproc (dir, pos_repos, update_dir)
char *dir;
char *pos_repos;
char *update_dir;
{
/* XXX - check for dirs we don't want to process??? */
if (!quiet)
error (0, 0, "Diffing %s", update_dir);
return (R_PROCESS);
}
/*
* Concoct the proper exit status.
*/
/* ARGSUSED */
static int
diff_dirleaveproc (dir, err, update_dir)
char *dir;
int err;
char *update_dir;
{
return (diff_errors);
}
/*
* verify that a file is different 0=same 1=different
*/
static int
diff_file_nodiff (file, repository, entries, srcfiles, vers)
char *file;
char *repository;
List *entries;
List *srcfiles;
Vers_TS *vers;
{
Vers_TS *xvers;
char tmp[L_tmpnam+1];
/* free up any old use_rev* variables and reset 'em */
if (use_rev1)
free (use_rev1);
if (use_rev2)
free (use_rev2);
use_rev1 = use_rev2 = (char *) NULL;
if (diff_rev1 || diff_date1)
{
/* special handling for TAG_HEAD */
if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0)
use_rev1 = xstrdup (vers->vn_rcs);
else
{
xvers = Version_TS (repository, (char *) NULL, diff_rev1,
diff_date1, file, 1, 0, entries, srcfiles);
if (xvers->vn_rcs == NULL)
{
if (diff_rev1)
error (0, 0, "tag %s is not in file %s", diff_rev1, file);
else
error (0, 0, "no revision for date %s in file %s",
diff_date1, file);
return (1);
}
use_rev1 = xstrdup (xvers->vn_rcs);
freevers_ts (&xvers);
}
}
if (diff_rev2 || diff_date2)
{
/* special handling for TAG_HEAD */
if (diff_rev2 && strcmp (diff_rev2, TAG_HEAD) == 0)
use_rev2 = xstrdup (vers->vn_rcs);
else
{
xvers = Version_TS (repository, (char *) NULL, diff_rev2,
diff_date2, file, 1, 0, entries, srcfiles);
if (xvers->vn_rcs == NULL)
{
if (diff_rev1)
error (0, 0, "tag %s is not in file %s", diff_rev2, file);
else
error (0, 0, "no revision for date %s in file %s",
diff_date2, file);
return (1);
}
use_rev2 = xstrdup (xvers->vn_rcs);
freevers_ts (&xvers);
}
/* now, see if we really need to do the diff */
return (strcmp (use_rev1, use_rev2) == 0);
}
if (use_rev1 == NULL || strcmp (use_rev1, vers->vn_user) == 0)
{
if (strcmp (vers->ts_rcs, vers->ts_user) == 0 &&
(!(*options) || strcmp (options, vers->options) == 0))
{
return (1);
}
if (use_rev1 == NULL)
use_rev1 = xstrdup (vers->vn_user);
}
/*
* with 0 or 1 -r option specified, run a quick diff to see if we
* should bother with it at all.
*/
run_setup ("%s%s -p -q %s -r%s", Rcsbin, RCS_CO,
*options ? options : vers->options, use_rev1);
run_arg (vers->srcfile->path);
switch (run_exec (RUN_TTY, tmpnam (tmp), RUN_TTY, RUN_REALLY))
{
case 0: /* everything ok */
if (xcmp (file, tmp) == 0)
{
(void) unlink (tmp);
return (1);
}
break;
case -1: /* fork failed */
(void) unlink (tmp);
error (1, errno, "fork failed during checkout of %s",
vers->srcfile->path);
default:
break;
}
(void) unlink (tmp);
return (0);
}

View File

@ -0,0 +1,488 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* Entries file to Files file
*
* Creates the file Files containing the names that comprise the project, from
* the Entries file.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)entries.c 1.37 92/03/31";
#endif
#if __STDC__
static Node *AddEntryNode (List * list, char *name, char *version,
char *timestamp, char *options, char *tag,
char *date);
#else
static Node *AddEntryNode ();
#endif /* __STDC__ */
static FILE *entfile;
static char *entfilename; /* for error messages */
/*
* Write out the line associated with a node of an entries file
*/
static int
write_ent_proc (node)
Node *node;
{
Entnode *p;
p = (Entnode *) node->data;
if (fprintf (entfile, "/%s/%s/%s/%s/", node->key, p->version,
p->timestamp, p->options) == EOF)
error (1, errno, "cannot write %s", entfilename);
if (p->tag)
{
if (fprintf (entfile, "T%s\n", p->tag) == EOF)
error (1, errno, "cannot write %s", entfilename);
}
else if (p->date)
{
if (fprintf (entfile, "D%s\n", p->date) == EOF)
error (1, errno, "cannot write %s", entfilename);
}
else if (fprintf (entfile, "\n") == EOF)
error (1, errno, "cannot write %s", entfilename);
return (0);
}
/*
* write out the current entries file given a list, making a backup copy
* first of course
*/
static void
write_entries (list)
List *list;
{
/* open the new one and walk the list writing entries */
entfilename = CVSADM_ENTBAK;
entfile = open_file (entfilename, "w+");
(void) walklist (list, write_ent_proc);
if (fclose (entfile) == EOF)
error (1, errno, "error closing %s", entfilename);
/* now, atomically (on systems that support it) rename it */
rename_file (entfilename, CVSADM_ENT);
}
/*
* Removes the argument file from the Entries file if necessary.
*/
void
Scratch_Entry (list, fname)
List *list;
char *fname;
{
Node *node;
if (trace)
(void) fprintf (stderr, "-> Scratch_Entry(%s)\n", fname);
/* hashlookup to see if it is there */
if ((node = findnode (list, fname)) != NULL)
{
delnode (node); /* delete the node */
if (!noexec)
write_entries (list); /* re-write the file */
}
}
/*
* Enters the given file name/version/time-stamp into the Entries file,
* removing the old entry first, if necessary.
*/
void
Register (list, fname, vn, ts, options, tag, date)
List *list;
char *fname;
char *vn;
char *ts;
char *options;
char *tag;
char *date;
{
Node *node;
if (trace)
(void) fprintf (stderr, "-> Register(%s, %s, %s, %s, %s %s)\n",
fname, vn, ts, options, tag ? tag : "",
date ? date : "");
/* was it already there? */
if ((node = findnode (list, fname)) != NULL)
{
/* take it out */
delnode (node);
/* add the new one and re-write the file */
(void) AddEntryNode (list, fname, vn, ts, options, tag, date);
if (!noexec)
write_entries (list);
}
else
{
/* add the new one */
node = AddEntryNode (list, fname, vn, ts, options, tag, date);
if (!noexec)
{
/* append it to the end */
entfilename = CVSADM_ENT;
entfile = open_file (entfilename, "a");
(void) write_ent_proc (node);
if (fclose (entfile) == EOF)
error (1, errno, "error closing %s", entfilename);
}
}
}
/*
* Node delete procedure for list-private sticky dir tag/date info
*/
static void
freesdt (p)
Node *p;
{
struct stickydirtag *sdtp;
sdtp = (struct stickydirtag *) p->data;
if (sdtp->tag)
free (sdtp->tag);
if (sdtp->date)
free (sdtp->date);
if (sdtp->options)
free (sdtp->options);
free ((char *) sdtp);
}
/*
* Read the entries file into a list, hashing on the file name.
*/
List *
ParseEntries (aflag)
int aflag;
{
List *entries;
char line[MAXLINELEN];
char *cp, *user, *vn, *ts, *options;
char *tag_or_date, *tag, *date;
char *dirtag, *dirdate;
int lineno = 0;
FILE *fpin;
/* get a fresh list... */
entries = getlist ();
/*
* Parse the CVS/Tag file, to get any default tag/date settings. Use
* list-private storage to tuck them away for Version_TS().
*/
ParseTag (&dirtag, &dirdate);
if (aflag || dirtag || dirdate)
{
struct stickydirtag *sdtp;
sdtp = (struct stickydirtag *) xmalloc (sizeof (*sdtp));
bzero ((char *) sdtp, sizeof (*sdtp));
sdtp->aflag = aflag;
sdtp->tag = xstrdup (dirtag);
sdtp->date = xstrdup (dirdate);
/* feed it into the list-private area */
entries->list->data = (char *) sdtp;
entries->list->delproc = freesdt;
}
again:
fpin = fopen (CVSADM_ENT, "r");
if (fpin == NULL)
error (0, errno, "cannot open %s for reading", CVSADM_ENT);
else
{
while (fgets (line, sizeof (line), fpin) != NULL)
{
lineno++;
if (line[0] == '/')
{
user = line + 1;
if ((cp = index (user, '/')) == NULL)
continue;
*cp++ = '\0';
vn = cp;
if ((cp = index (vn, '/')) == NULL)
continue;
*cp++ = '\0';
ts = cp;
if ((cp = index (ts, '/')) == NULL)
continue;
*cp++ = '\0';
options = cp;
if ((cp = index (options, '/')) == NULL)
continue;
*cp++ = '\0';
tag_or_date = cp;
if ((cp = index (tag_or_date, '\n')) == NULL)
continue;
*cp = '\0';
tag = (char *) NULL;
date = (char *) NULL;
if (*tag_or_date == 'T')
tag = tag_or_date + 1;
else if (*tag_or_date == 'D')
date = tag_or_date + 1;
(void) AddEntryNode (entries, user, vn, ts, options, tag, date);
}
else
{
/* try conversion only on first line */
if (lineno == 1)
{
(void) fclose (fpin);
check_entries ((char *) NULL);
goto again;
}
}
}
}
/* clean up and return */
if (fpin)
(void) fclose (fpin);
if (dirtag)
free (dirtag);
if (dirdate)
free (dirdate);
return (entries);
}
/*
* Look at the entries file to determine if it is in the old entries format.
* If so, convert it to the new format.
*/
void
check_entries (dir)
char *dir;
{
FILE *fpin, *fpout;
char tmp[MAXLINELEN];
char line[MAXLINELEN];
char entname[MAXLINELEN];
char entbak[MAXLINELEN];
char *cp, *user, *rev, *ts, *opt;
if (dir != NULL)
{
(void) sprintf (entname, "%s/%s", dir, CVSADM_ENT);
(void) sprintf (entbak, "%s/%s", dir, CVSADM_ENTBAK);
}
else
{
(void) strcpy (entname, CVSADM_ENT);
(void) strcpy (entbak, CVSADM_ENTBAK);
}
fpin = open_file (entname, "r");
if (fgets (line, sizeof (line), fpin) == NULL)
{
(void) fclose (fpin);
return;
}
(void) fclose (fpin);
if (line[0] != '/')
{
rename_file (entname, entbak);
fpin = open_file (entbak, "r");
fpout = open_file (entname, "w+");
while (fgets (line, sizeof (line), fpin) != NULL)
{
if (line[0] == '/')
{
if (fputs (line, fpout) == EOF)
error (1, errno, "cannot write %s", CVSADM_ENT);
continue;
}
rev = line;
if ((ts = index (line, '|')) == NULL)
continue;
*ts++ = '\0';
if ((user = rindex (ts, ' ')) == NULL)
continue;
*user++ = '\0';
if ((cp = index (user, '|')) == NULL)
continue;
*cp = '\0';
opt = "";
#ifdef HAVE_RCS5
#ifdef HAD_RCS4
opt = "-V4";
#endif
#endif
if (fprintf (fpout, "/%s/%s/%s/%s/\n", user, rev, ts, opt) == EOF)
error (1, errno, "cannot write %s", CVSADM_ENT);
}
(void) fclose (fpin);
if (fclose (fpout) == EOF)
error (1, errno, "cannot close %s", entname);
/* clean up any old Files or Mod files */
if (dir != NULL)
(void) sprintf (tmp, "%s/%s", dir, CVSADM_FILE);
else
(void) strcpy (tmp, CVSADM_FILE);
if (isfile (tmp))
(void) unlink (tmp);
if (dir != NULL)
(void) sprintf (tmp, "%s/%s", dir, CVSADM_MOD);
else
(void) strcpy (tmp, CVSADM_MOD);
if (isfile (tmp))
(void) unlink (tmp);
}
}
/*
* Free up the memory associated with the data section of an ENTRIES type
* node
*/
static void
Entries_delproc (node)
Node *node;
{
Entnode *p;
p = (Entnode *) node->data;
free (p->version);
free (p->timestamp);
free (p->options);
if (p->tag)
free (p->tag);
if (p->date)
free (p->date);
free ((char *) p);
}
/*
* Get an Entries file list node, initialize it, and add it to the specified
* list
*/
static Node *
AddEntryNode (list, name, version, timestamp, options, tag, date)
List *list;
char *name;
char *version;
char *timestamp;
char *options;
char *tag;
char *date;
{
Node *p;
Entnode *entdata;
/* get a node and fill in the regular stuff */
p = getnode ();
p->type = ENTRIES;
p->delproc = Entries_delproc;
/* this one gets a key of the name for hashing */
p->key = xstrdup (name);
/* malloc the data parts and fill them in */
p->data = xmalloc (sizeof (Entnode));
entdata = (Entnode *) p->data;
entdata->version = xstrdup (version);
entdata->timestamp = xstrdup (timestamp);
entdata->options = xstrdup (options);
if (entdata->options == NULL)
entdata->options = xstrdup ("");/* must be non-NULL */
entdata->tag = xstrdup (tag);
entdata->date = xstrdup (date);
/* put the node into the list */
if (addnode (list, p) != 0)
error (0, 0, "Duplicate filename in entries file (%s) -- ignored",
name);
return (p);
}
/*
* Write out/Clear the CVS/Tag file.
*/
void
WriteTag (dir, tag, date)
char *dir;
char *tag;
char *date;
{
FILE *fout;
char tmp[PATH_MAX];
if (noexec)
return;
if (dir == NULL)
(void) strcpy (tmp, CVSADM_TAG);
else
(void) sprintf (tmp, "%s/%s", dir, CVSADM_TAG);
if (tag || date)
{
fout = open_file (tmp, "w+");
if (tag)
{
if (fprintf (fout, "T%s\n", tag) == EOF)
error (1, errno, "write to %s failed", tmp);
}
else
{
if (fprintf (fout, "D%s\n", date) == EOF)
error (1, errno, "write to %s failed", tmp);
}
if (fclose (fout) == EOF)
error (1, errno, "cannot close %s", tmp);
}
else
(void) unlink_file (tmp);
}
/*
* Parse the CVS/Tag file for the current directory.
*/
void
ParseTag (tagp, datep)
char **tagp;
char **datep;
{
FILE *fp;
char line[MAXLINELEN];
char *cp;
if (tagp)
*tagp = (char *) NULL;
if (datep)
*datep = (char *) NULL;
fp = fopen (CVSADM_TAG, "r");
if (fp)
{
if (fgets (line, sizeof (line), fp) != NULL)
{
if ((cp = rindex (line, '\n')) != NULL)
*cp = '\0';
if (*line == 'T' && tagp)
*tagp = xstrdup (line + 1);
else if (*line == 'D' && datep)
*datep = xstrdup (line + 1);
}
(void) fclose (fp);
}
}

View File

@ -0,0 +1,272 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* Find Names
*
* Finds all the pertinent file names, both from the administration and from the
* repository
*
* Find Dirs
*
* Finds all pertinent sub-directories of the checked out instantiation and the
* repository (and optionally the attic)
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)find_names.c 1.38 92/04/10";
#endif
#if __STDC__
static int find_dirs (char *dir, List * list, int checkadm);
static int find_rcs (char *dir, List * list);
#else
static int find_rcs ();
static int find_dirs ();
#endif /* __STDC__ */
static List *filelist;
/*
* add the key from entry on entries list to the files list
*/
static int
add_entries_proc (node)
Node *node;
{
Node *fnode;
fnode = getnode ();
fnode->type = FILES;
fnode->key = xstrdup (node->key);
if (addnode (filelist, fnode) != 0)
freenode (fnode);
return (0);
}
/*
* compare two files list node (for sort)
*/
static int
fsortcmp (p, q)
Node *p, *q;
{
return (strcmp (p->key, q->key));
}
List *
Find_Names (repository, which, aflag, optentries)
char *repository;
int which;
int aflag;
List **optentries;
{
List *entries;
List *files;
char dir[PATH_MAX];
/* make a list for the files */
files = filelist = getlist ();
/* look at entries (if necessary) */
if (which & W_LOCAL)
{
/* parse the entries file (if it exists) */
entries = ParseEntries (aflag);
if (entries != NULL)
{
/* walk the entries file adding elements to the files list */
(void) walklist (entries, add_entries_proc);
/* if our caller wanted the entries list, return it; else free it */
if (optentries != NULL)
*optentries = entries;
else
dellist (&entries);
}
}
if ((which & W_REPOS) && repository && !isreadable (CVSADM_ENTSTAT))
{
/* search the repository */
if (find_rcs (repository, files) != 0)
error (1, errno, "cannot open directory %s", repository);
/* search the attic too */
if (which & W_ATTIC)
{
(void) sprintf (dir, "%s/%s", repository, CVSATTIC);
(void) find_rcs (dir, files);
}
}
/* sort the list into alphabetical order and return it */
sortlist (files, fsortcmp);
return (files);
}
/*
* create a list of directories to traverse from the current directory
*/
List *
Find_Dirs (repository, which)
char *repository;
int which;
{
List *dirlist;
/* make a list for the directories */
dirlist = getlist ();
/* find the local ones */
if (which & W_LOCAL)
{
/* look only for CVS controlled sub-directories */
if (find_dirs (".", dirlist, 1) != 0)
error (1, errno, "cannot open current directory");
}
/* look for sub-dirs in the repository */
if ((which & W_REPOS) && repository)
{
/* search the repository */
if (find_dirs (repository, dirlist, 0) != 0)
error (1, errno, "cannot open directory %s", repository);
#ifdef ATTIC_DIR_SUPPORT /* XXX - FIXME */
/* search the attic too */
if (which & W_ATTIC)
{
char dir[PATH_MAX];
(void) sprintf (dir, "%s/%s", repository, CVSATTIC);
(void) find_dirs (dir, dirlist, 0);
}
#endif
}
/* sort the list into alphabetical order and return it */
sortlist (dirlist, fsortcmp);
return (dirlist);
}
/*
* Finds all the ,v files in the argument directory, and adds them to the
* files list. Returns 0 for success and non-zero if the argument directory
* cannot be opened.
*/
static int
find_rcs (dir, list)
char *dir;
List *list;
{
Node *p;
CONST char *regex_err;
char line[50];
struct direct *dp;
DIR *dirp;
/* set up to read the dir */
if ((dirp = opendir (dir)) == NULL)
return (1);
/* set up a regular expression to find the ,v files */
(void) sprintf (line, ".*%s$", RCSEXT);
if ((regex_err = re_comp (line)) != NULL)
error (1, 0, "%s", regex_err);
/* read the dir, grabbing the ,v files */
while ((dp = readdir (dirp)) != NULL)
{
if (re_exec (dp->d_name))
{
char *comma;
comma = rindex (dp->d_name, ','); /* strip the ,v */
*comma = '\0';
p = getnode ();
p->type = FILES;
p->key = xstrdup (dp->d_name);
if (addnode (list, p) != 0)
freenode (p);
}
}
(void) closedir (dirp);
return (0);
}
/*
* Finds all the subdirectories of the argument dir and adds them to the
* specified list. Sub-directories without a CVS administration directory
* are optionally ignored Returns 0 for success or 1 on error.
*/
static int
find_dirs (dir, list, checkadm)
char *dir;
List *list;
int checkadm;
{
Node *p;
CONST char *regex_err;
char tmp[PATH_MAX];
char admdir[PATH_MAX];
struct direct *dp;
DIR *dirp;
/* build a regex to blow off ,v files */
(void) sprintf (tmp, ".*%s$", RCSEXT);
if ((regex_err = re_comp (tmp)) != NULL)
error (1, 0, "%s", regex_err);
/* set up to read the dir */
if ((dirp = opendir (dir)) == NULL)
return (1);
/* read the dir, grabbing sub-dirs */
while ((dp = readdir (dirp)) != NULL)
{
if (strcmp (dp->d_name, ".") == 0 ||
strcmp (dp->d_name, "..") == 0 ||
strcmp (dp->d_name, CVSATTIC) == 0 ||
strcmp (dp->d_name, CVSLCK) == 0 ||
re_exec (dp->d_name)) /* don't bother stating ,v files */
continue;
(void) sprintf (tmp, "%s/%s", dir, dp->d_name);
if (isdir (tmp))
{
/* check for administration directories (if needed) */
if (checkadm)
{
/* blow off symbolic links to dirs in local dir */
if (islink (tmp))
continue;
/* check for new style */
(void) sprintf (admdir, "%s/%s", tmp, CVSADM);
if (!isdir (admdir))
{
/* and old style */
(void) sprintf (admdir, "%s/%s", tmp, OCVSADM);
if (!isdir (admdir))
continue;
}
}
/* put it in the list */
p = getnode ();
p->type = DIRS;
p->key = xstrdup (dp->d_name);
if (addnode (list, p) != 0)
freenode (p);
}
}
(void) closedir (dirp);
return (0);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,227 @@
/*
* .cvsignore file support contributed by David G. Grubbs <dgg@ksr.com>
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)ignore.c 1.13 92/04/03";
#endif
/*
* Ignore file section.
*
* "!" may be included any time to reset the list (i.e. ignore nothing);
* "*" may be specified to ignore everything. It stays as the first
* element forever, unless a "!" clears it out.
*/
static char **ign_list; /* List of files to ignore in update
* and import */
static char **s_ign_list = NULL;
static int ign_count; /* Number of active entries */
static int s_ign_count = 0;
static int ign_size; /* This many slots available (plus
* one for a NULL) */
static int ign_hold; /* Index where first "temporary" item
* is held */
char *ign_default = ". .. core RCSLOG tags TAGS RCS SCCS .make.state .nse_depinfo #* .#* cvslog.* ,* CVS* .del-* *.a *.o *.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej";
#define IGN_GROW 16 /* grow the list by 16 elements at a
* time */
/*
* To the "ignore list", add the hard-coded default ignored wildcards above,
* the wildcards found in $CVSROOT/CVSROOT/cvsignore, the wildcards found in
* ~/.cvsignore and the wildcards found in the CVSIGNORE environment
* variable.
*/
void
ign_setup ()
{
extern char *getenv ();
struct passwd *pw;
char file[PATH_MAX];
char *tmp;
/* Start with default list and special case */
tmp = xstrdup (ign_default);
ign_add (tmp, 0);
free (tmp);
/* Then add entries found in repository, if it exists */
(void) sprintf (file, "%s/%s/%s", CVSroot, CVSROOTADM, CVSROOTADM_IGNORE);
if (isfile (file))
ign_add_file (file, 0);
/* Then add entries found in home dir, (if user has one) and file exists */
if ((pw = (struct passwd *) getpwuid (getuid ())) && pw->pw_dir)
{
(void) sprintf (file, "%s/%s", pw->pw_dir, CVSDOTIGNORE);
if (isfile (file))
ign_add_file (file, 0);
}
/* Then add entries found in CVSIGNORE environment variable. */
ign_add (getenv (IGNORE_ENV), 0);
/* Later, add ignore entries found in -I arguments */
}
/*
* Open a file and read lines, feeding each line to a line parser. Arrange
* for keeping a temporary list of wildcards at the end, if the "hold"
* argument is set.
*/
void
ign_add_file (file, hold)
char *file;
int hold;
{
FILE *fp;
char line[1024];
/* restore the saved list (if any) */
if (s_ign_list != NULL)
{
int i;
for (i = 0; i < s_ign_count; i++)
ign_list[i] = s_ign_list[i];
ign_count = s_ign_count;
ign_list[ign_count] = NULL;
s_ign_count = 0;
free (s_ign_list);
s_ign_list = NULL;
}
/* is this a temporary ignore file? */
if (hold)
{
/* re-set if we had already done a temporary file */
if (ign_hold)
{
int i;
for (i = ign_hold; i < ign_count; i++)
free (ign_list[i]);
ign_count = ign_hold;
ign_list[ign_count] = NULL;
}
else
{
ign_hold = ign_count;
}
}
/* load the file */
if (!(fp = fopen (file, "r")))
return;
while (fgets (line, sizeof (line), fp))
ign_add (line, hold);
(void) fclose (fp);
}
/* Parse a line of space-separated wildcards and add them to the list. */
void
ign_add (ign, hold)
char *ign;
int hold;
{
if (!ign || !*ign)
return;
for (; *ign; ign++)
{
char *mark;
char save;
/* ignore whitespace before the token */
if (isspace (*ign))
continue;
/*
* if we find a single character !, we must re-set the ignore list
* (saving it if necessary). We also catch * as a special case in a
* global ignore file as an optimization
*/
if (isspace (*(ign + 1)) && (*ign == '!' || *ign == '*'))
{
if (!hold)
{
/* permanently reset the ignore list */
int i;
for (i = 0; i < ign_count; i++)
free (ign_list[i]);
ign_count = 0;
ign_list[0] = NULL;
/* if we are doing a '!', continue; otherwise add the '*' */
if (*ign == '!')
continue;
}
else if (*ign == '!')
{
/* temporarily reset the ignore list */
int i;
if (ign_hold)
{
for (i = ign_hold; i < ign_count; i++)
free (ign_list[i]);
ign_hold = 0;
}
s_ign_list = (char **) xmalloc (ign_count * sizeof (char *));
for (i = 0; i < ign_count; i++)
s_ign_list[i] = ign_list[i];
s_ign_count = ign_count;
ign_count = 0;
ign_list[0] = NULL;
continue;
}
}
/* If we have used up all the space, add some more */
if (ign_count >= ign_size)
{
ign_size += IGN_GROW;
ign_list = (char **) xrealloc ((char *) ign_list,
(ign_size + 1) * sizeof (char *));
}
/* find the end of this token */
for (mark = ign; *mark && !isspace (*mark); mark++)
/* do nothing */ ;
save = *mark;
*mark = '\0';
ign_list[ign_count++] = xstrdup (ign);
ign_list[ign_count] = NULL;
*mark = save;
if (save)
ign = mark;
else
ign = mark - 1;
}
}
/* Return 1 if the given filename should be ignored by update or import. */
int
ign_name (name)
char *name;
{
char **cpp = ign_list;
if (cpp == NULL)
return (0);
while (*cpp)
if (fnmatch (*cpp++, name, 0) == 0)
return (1);
return (0);
}

View File

@ -0,0 +1,974 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* "import" checks in the vendor release located in the current directory into
* the CVS source repository. The CVS vendor branch support is utilized.
*
* At least three arguments are expected to follow the options:
* repository Where the source belongs relative to the CVSROOT
* VendorTag Vendor's major tag
* VendorReleTag Tag for this particular release
*
* Additional arguments specify more Vendor Release Tags.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)import.c 1.52 92/03/31";
#endif
#define FILE_HOLDER ".#cvsxxx"
#if __STDC__
static char *get_comment (char *user);
static int add_rcs_file (char *message, char *rcs, char *user, char *vtag,
int targc, char *targv[]);
static int expand_at_signs (char *buf, off_t size, FILE *fp);
static int add_rev (char *message, char *rcs, char *vfile, char *vers);
static int add_tags (char *rcs, char *vfile, char *vtag, int targc,
char *targv[]);
static int import_descend (char *message, char *vtag, int targc, char *targv[]);
static int import_descend_dir (char *message, char *dir, char *vtag,
int targc, char *targv[]);
static int process_import_file (char *message, char *vfile, char *vtag,
int targc, char *targv[]);
static int update_rcs_file (char *message, char *vfile, char *vtag, int targc,
char *targv[]);
static void add_log (int ch, char *fname);
#else
static int import_descend ();
static int process_import_file ();
static int update_rcs_file ();
static int add_rev ();
static int add_tags ();
static char *get_comment ();
static int add_rcs_file ();
static int expand_at_signs ();
static void add_log ();
static int import_descend_dir ();
#endif /* __STDC__ */
static int repos_len;
static char vhead[50];
static char vbranch[50];
static FILE *logfp;
static char repository[PATH_MAX];
static int conflicts;
static char *import_usage[] =
{
"Usage: %s %s [-Qq] [-I ign] [-m msg] [-b branch]\n",
" repository vendor-tag release-tags...\n",
"\t-Q\tReally quiet.\n",
"\t-q\tSomewhat quiet.\n",
"\t-I ign\tMore files to ignore (! to reset).\n",
"\t-b bra\tVendor branch id.\n",
"\t-m msg\tLog message.\n",
NULL
};
int
import (argc, argv)
int argc;
char *argv[];
{
char message[MAXMESGLEN];
char tmpfile[L_tmpnam+1];
char *cp;
int i, c, msglen, err;
List *ulist;
Node *p;
if (argc == -1)
usage (import_usage);
ign_setup ();
(void) strcpy (vbranch, CVSBRANCH);
message[0] = '\0';
optind = 1;
while ((c = gnu_getopt (argc, argv, "Qqb:m:I:")) != -1)
{
switch (c)
{
case 'Q':
really_quiet = 1;
/* FALL THROUGH */
case 'q':
quiet = 1;
break;
case 'b':
(void) strcpy (vbranch, optarg);
break;
case 'm':
#ifdef FORCE_USE_EDITOR
use_editor = TRUE;
#else
use_editor = FALSE;
#endif
if (strlen (optarg) >= (sizeof (message) - 1))
{
error (0, 0, "warning: message too long; truncated!");
(void) strncpy (message, optarg, sizeof (message));
message[sizeof (message) - 2] = '\0';
}
else
(void) strcpy (message, optarg);
break;
case 'I':
ign_add (optarg, 0);
break;
case '?':
default:
usage (import_usage);
break;
}
}
argc -= optind;
argv += optind;
if (argc < 3)
usage (import_usage);
for (i = 1; i < argc; i++) /* check the tags for validity */
RCS_check_tag (argv[i]);
/* XXX - this should be a module, not just a pathname */
if (argv[0][0] != '/')
{
if (CVSroot == NULL)
{
error (0, 0, "missing CVSROOT environment variable\n");
error (1, 0, "Set it or specify the '-d' option to %s.",
program_name);
}
(void) sprintf (repository, "%s/%s", CVSroot, argv[0]);
repos_len = strlen (CVSroot);
}
else
{
(void) strcpy (repository, argv[0]);
repos_len = 0;
}
/*
* Consistency checks on the specified vendor branch. It must be
* composed of only numbers and dots ('.'). Also, for now we only
* support branching to a single level, so the specified vendor branch
* must only have two dots in it (like "1.1.1").
*/
for (cp = vbranch; *cp != '\0'; cp++)
if (!isdigit (*cp) && *cp != '.')
error (1, 0, "%s is not a numeric branch", vbranch);
if (numdots (vbranch) != 2)
error (1, 0, "Only branches with two dots are supported: %s", vbranch);
(void) strcpy (vhead, vbranch);
cp = rindex (vhead, '.');
*cp = '\0';
if (use_editor)
do_editor ((char *) NULL, message, repository, (List *) NULL);
msglen = strlen (message);
if (msglen == 0 || message[msglen - 1] != '\n')
{
message[msglen] = '\n';
message[msglen + 1] = '\0';
}
/*
* Make all newly created directories writable. Should really use a more
* sophisticated security mechanism here.
*/
(void) umask (2);
make_directories (repository);
/* Create the logfile that will be logged upon completion */
if ((logfp = fopen (tmpnam (tmpfile), "w+")) == NULL)
error (1, errno, "cannot create temporary file `%s'", tmpfile);
(void) unlink (tmpfile); /* to be sure it goes away */
(void) fprintf (logfp, "\nVendor Tag:\t%s\n", argv[1]);
(void) fprintf (logfp, "Release Tags:\t");
for (i = 2; i < argc; i++)
(void) fprintf (logfp, "%s\n\t\t", argv[i]);
(void) fprintf (logfp, "\n");
/* Just Do It. */
err = import_descend (message, argv[1], argc - 2, argv + 2);
if (conflicts)
{
if (!really_quiet)
{
(void) printf ("\n%d conflicts created by this import.\n",
conflicts);
(void) printf ("Use the following command to help the merge:\n\n");
(void) printf ("\t%s checkout -j%s:yesterday -j%s %s\n\n",
program_name, argv[1], argv[1], argv[0]);
}
(void) fprintf (logfp, "\n%d conflicts created by this import.\n",
conflicts);
(void) fprintf (logfp,
"Use the following command to help the merge:\n\n");
(void) fprintf (logfp, "\t%s checkout -j%s:yesterday -j%s %s\n\n",
program_name, argv[1], argv[1], argv[0]);
}
else
{
if (!really_quiet)
(void) printf ("\nNo conflicts created by this import\n\n");
(void) fprintf (logfp, "\nNo conflicts created by this import\n\n");
}
/*
* Write out the logfile and clean up.
*/
ulist = getlist ();
p = getnode ();
p->type = UPDATE;
p->delproc = update_delproc;
p->key = xstrdup ("- Imported sources");
p->data = (char *) T_TITLE;
(void) addnode (ulist, p);
Update_Logfile (repository, message, vbranch, logfp, ulist);
dellist (&ulist);
(void) fclose (logfp);
return (err);
}
/*
* process all the files in ".", then descend into other directories.
*/
static int
import_descend (message, vtag, targc, targv)
char *message;
char *vtag;
int targc;
char *targv[];
{
DIR *dirp;
struct direct *dp;
int err = 0;
int has_dirs = 0;
/* first, load up any per-directory ignore lists */
ign_add_file (CVSDOTIGNORE, 1);
if ((dirp = opendir (".")) == NULL)
{
err++;
}
else
{
while ((dp = readdir (dirp)) != NULL)
{
if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0)
continue;
if (ign_name (dp->d_name))
{
add_log ('I', dp->d_name);
continue;
}
if (isdir (dp->d_name))
{
has_dirs = 1;
}
else
{
if (islink (dp->d_name))
{
add_log ('L', dp->d_name);
err++;
}
else
{
err += process_import_file (message, dp->d_name,
vtag, targc, targv);
}
}
}
(void) closedir (dirp);
}
if (has_dirs)
{
if ((dirp = opendir (".")) == NULL)
err++;
else
{
while ((dp = readdir (dirp)) != NULL)
{
if (ign_name (dp->d_name) || !isdir (dp->d_name))
continue;
err += import_descend_dir (message, dp->d_name,
vtag, targc, targv);
}
(void) closedir (dirp);
}
}
return (err);
}
/*
* Process the argument import file.
*/
static int
process_import_file (message, vfile, vtag, targc, targv)
char *message;
char *vfile;
char *vtag;
int targc;
char *targv[];
{
char attic_name[PATH_MAX];
char rcs[PATH_MAX];
(void) sprintf (rcs, "%s/%s%s", repository, vfile, RCSEXT);
if (!isfile (rcs))
{
(void) sprintf (attic_name, "%s/%s/%s%s", repository, CVSATTIC,
vfile, RCSEXT);
if (!isfile (attic_name))
{
/*
* A new import source file; it doesn't exist as a ,v within the
* repository nor in the Attic -- create it anew.
*/
add_log ('N', vfile);
return (add_rcs_file (message, rcs, vfile, vtag, targc, targv));
}
}
/*
* an rcs file exists. have to do things the official, slow, way.
*/
return (update_rcs_file (message, vfile, vtag, targc, targv));
}
/*
* The RCS file exists; update it by adding the new import file to the
* (possibly already existing) vendor branch.
*/
static int
update_rcs_file (message, vfile, vtag, targc, targv)
char *message;
char *vfile;
char *vtag;
int targc;
char *targv[];
{
Vers_TS *vers;
char letter;
int ierrno;
vers = Version_TS (repository, (char *) NULL, vbranch, (char *) NULL, vfile,
1, 0, (List *) NULL, (List *) NULL);
if (vers->vn_rcs != NULL)
{
char xtmpfile[50];
int different;
int retcode = 0;
/* XXX - should be more unique */
(void) sprintf (xtmpfile, "/tmp/%s", FILE_HOLDER);
/*
* The rcs file does have a revision on the vendor branch. Compare
* this revision with the import file; if they match exactly, there
* is no need to install the new import file as a new revision to the
* branch. Just tag the revision with the new import tags.
*
* This is to try to cut down the number of "C" conflict messages for
* locally modified import source files.
*/
#ifdef HAVE_RCS5
run_setup ("%s%s -q -f -r%s -p -ko", Rcsbin, RCS_CO, vers->vn_rcs);
#else
run_setup ("%s%s -q -f -r%s -p", Rcsbin, RCS_CO, vers->vn_rcs);
#endif
run_arg (vers->srcfile->path);
if ((retcode = run_exec (RUN_TTY, xtmpfile, RUN_TTY,
RUN_NORMAL|RUN_REALLY)) != 0)
{
ierrno = errno;
fperror (logfp, 0, retcode == -1 ? ierrno : 0,
"ERROR: cannot co revision %s of file %s", vers->vn_rcs,
vers->srcfile->path);
error (0, retcode == -1 ? ierrno : 0,
"ERROR: cannot co revision %s of file %s", vers->vn_rcs,
vers->srcfile->path);
(void) unlink_file (xtmpfile);
return (1);
}
different = xcmp (xtmpfile, vfile);
(void) unlink_file (xtmpfile);
if (!different)
{
int retval = 0;
/*
* The two files are identical. Just update the tags, print the
* "U", signifying that the file has changed, but needs no
* attention, and we're done.
*/
if (add_tags (vers->srcfile->path, vfile, vtag, targc, targv))
retval = 1;
add_log ('U', vfile);
freevers_ts (&vers);
return (retval);
}
}
/* We may have failed to parse the RCS file; check just in case */
if (vers->srcfile == NULL || add_rev (message, vers->srcfile->path,
vfile, vers->vn_rcs) ||
add_tags (vers->srcfile->path, vfile, vtag, targc, targv))
{
freevers_ts (&vers);
return (1);
}
if (vers->srcfile->branch == NULL ||
strcmp (vers->srcfile->branch, vbranch) != 0)
{
conflicts++;
letter = 'C';
}
else
letter = 'U';
add_log (letter, vfile);
freevers_ts (&vers);
return (0);
}
/*
* Add the revision to the vendor branch
*/
static int
add_rev (message, rcs, vfile, vers)
char *message;
char *rcs;
char *vfile;
char *vers;
{
int locked, status, ierrno;
int retcode = 0;
if (noexec)
return (0);
locked = 0;
if (vers != NULL)
{
run_setup ("%s%s -q -l%s", Rcsbin, RCS, vbranch);
run_arg (rcs);
if ((retcode = run_exec (RUN_TTY, DEVNULL, DEVNULL, RUN_NORMAL)) == 0)
locked = 1;
else if (retcode == -1)
{
error (0, errno, "fork failed");
return (1);
}
}
if (link_file (vfile, FILE_HOLDER) < 0)
{
if (errno == EEXIST)
{
(void) unlink_file (FILE_HOLDER);
(void) link_file (vfile, FILE_HOLDER);
}
else
{
ierrno = errno;
fperror (logfp, 0, ierrno, "ERROR: cannot create link to %s", vfile);
error (0, ierrno, "ERROR: cannot create link to %s", vfile);
return (1);
}
}
run_setup ("%s%s -q -f -r%s", Rcsbin, RCS_CI, vbranch);
run_args ("-m%s", message);
run_arg (rcs);
status = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
ierrno = errno;
rename_file (FILE_HOLDER, vfile);
if (status)
{
if (!noexec)
{
fperror (logfp, 0, status == -1 ? ierrno : 0, "ERROR: Check-in of %s failed", rcs);
error (0, status == -1 ? ierrno : 0, "ERROR: Check-in of %s failed", rcs);
}
if (locked)
{
run_setup ("%s%s -q -u%s", Rcsbin, RCS, vbranch);
run_arg (rcs);
(void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
}
return (1);
}
return (0);
}
/*
* Add the vendor branch tag and all the specified import release tags to the
* RCS file. The vendor branch tag goes on the branch root (1.1.1) while the
* vendor release tags go on the newly added leaf of the branch (1.1.1.1,
* 1.1.1.2, ...).
*/
static int
add_tags (rcs, vfile, vtag, targc, targv)
char *rcs;
char *vfile;
char *vtag;
int targc;
char *targv[];
{
int i, ierrno;
Vers_TS *vers;
int retcode = 0;
if (noexec)
return (0);
run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, vtag, vbranch);
run_arg (rcs);
if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
{
ierrno = errno;
fperror (logfp, 0, retcode == -1 ? ierrno : 0,
"ERROR: Failed to set tag %s in %s", vtag, rcs);
error (0, retcode == -1 ? ierrno : 0,
"ERROR: Failed to set tag %s in %s", vtag, rcs);
return (1);
}
vers = Version_TS (repository, (char *) NULL, vtag, (char *) NULL, vfile,
1, 0, (List *) NULL, (List *) NULL);
for (i = 0; i < targc; i++)
{
run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, targv[i], vers->vn_rcs);
run_arg (rcs);
if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
{
ierrno = errno;
fperror (logfp, 0, retcode == -1 ? ierrno : 0,
"WARNING: Couldn't add tag %s to %s", targv[i], rcs);
error (0, retcode == -1 ? ierrno : 0,
"WARNING: Couldn't add tag %s to %s", targv[i], rcs);
}
}
freevers_ts (&vers);
return (0);
}
/*
* Stolen from rcs/src/rcsfnms.c, and adapted/extended.
*/
struct compair
{
char *suffix, *comlead;
};
struct compair comtable[] =
{
/*
* comtable pairs each filename suffix with a comment leader. The comment
* leader is placed before each line generated by the $Log keyword. This
* table is used to guess the proper comment leader from the working file's
* suffix during initial ci (see InitAdmin()). Comment leaders are needed for
* languages without multiline comments; for others they are optional.
*/
"a", "-- ", /* Ada */
"ada", "-- ",
"asm", ";; ", /* assembler (MS-DOS) */
"bat", ":: ", /* batch (MS-DOS) */
"c", " * ", /* C */
"c++", "// ", /* C++ in all its infinite guises */
"cc", "// ",
"cpp", "// ",
"cxx", "// ",
"cl", ";;; ", /* Common Lisp */
"cmd", ":: ", /* command (OS/2) */
"cmf", "c ", /* CM Fortran */
"cs", " * ", /* C* */
"csh", "# ", /* shell */
"e", "# ", /* efl */
"el", "; ", /* Emacs Lisp */
"f", "c ", /* Fortran */
"for", "c ",
"h", " * ", /* C-header */
"hh", "// ", /* C++ header */
"hpp", "// ",
"hxx", "// ",
"in", "# ", /* for Makefile.in */
"l", " * ", /* lex (conflict between lex and
* franzlisp) */
"mac", ";; ", /* macro (DEC-10, MS-DOS, PDP-11,
* VMS, etc) */
"me", ".\\\" ", /* me-macros t/nroff */
"ml", "; ", /* mocklisp */
"mm", ".\\\" ", /* mm-macros t/nroff */
"ms", ".\\\" ", /* ms-macros t/nroff */
"man", ".\\\" ", /* man-macros t/nroff */
"1", ".\\\" ", /* feeble attempt at man pages... */
"2", ".\\\" ",
"3", ".\\\" ",
"4", ".\\\" ",
"5", ".\\\" ",
"6", ".\\\" ",
"7", ".\\\" ",
"8", ".\\\" ",
"9", ".\\\" ",
"p", " * ", /* pascal */
"pas", " * ",
"pl", "# ", /* perl (conflict with Prolog) */
"ps", "% ", /* postscript */
"r", "# ", /* ratfor */
"red", "% ", /* psl/rlisp */
#ifdef sparc
"s", "! ", /* assembler */
#endif
#ifdef mc68000
"s", "| ", /* assembler */
#endif
#ifdef pdp11
"s", "/ ", /* assembler */
#endif
#ifdef vax
"s", "# ", /* assembler */
#endif
#ifdef __ksr__
"s", "# ", /* assembler */
"S", "# ", /* Macro assembler */
#endif
"sh", "# ", /* shell */
"sl", "% ", /* psl */
"tex", "% ", /* tex */
"y", " * ", /* yacc */
"ye", " * ", /* yacc-efl */
"yr", " * ", /* yacc-ratfor */
"", "# ", /* default for empty suffix */
NULL, "# " /* default for unknown suffix; */
/* must always be last */
};
static char *
get_comment (user)
char *user;
{
char *cp, *suffix;
char suffix_path[PATH_MAX];
int i;
cp = rindex (user, '.');
if (cp != NULL)
{
cp++;
/*
* Convert to lower-case, since we are not concerned about the
* case-ness of the suffix.
*/
(void) strcpy (suffix_path, cp);
for (cp = suffix_path; *cp; cp++)
if (isupper (*cp))
*cp = tolower (*cp);
suffix = suffix_path;
}
else
suffix = ""; /* will use the default */
for (i = 0;; i++)
{
if (comtable[i].suffix == NULL) /* default */
return (comtable[i].comlead);
if (strcmp (suffix, comtable[i].suffix) == 0)
return (comtable[i].comlead);
}
}
static int
add_rcs_file (message, rcs, user, vtag, targc, targv)
char *message;
char *rcs;
char *user;
char *vtag;
int targc;
char *targv[];
{
FILE *fprcs, *fpuser;
struct stat sb;
struct tm *ftm;
time_t now;
char altdate1[50], altdate2[50];
char *author, *buf;
int i, mode, ierrno, err = 0;
if (noexec)
return (0);
fprcs = open_file (rcs, "w+");
fpuser = open_file (user, "r");
/*
* putadmin()
*/
if (fprintf (fprcs, "head %s;\n", vhead) == EOF ||
fprintf (fprcs, "branch %s;\n", vbranch) == EOF ||
fprintf (fprcs, "access ;\n") == EOF ||
fprintf (fprcs, "symbols ") == EOF)
{
goto write_error;
}
for (i = targc - 1; i >= 0; i--) /* RCS writes the symbols backwards */
if (fprintf (fprcs, "%s:%s.1 ", targv[i], vbranch) == EOF)
goto write_error;
if (fprintf (fprcs, "%s:%s;\n", vtag, vbranch) == EOF ||
fprintf (fprcs, "locks ; strict;\n") == EOF ||
/* XXX - make sure @@ processing works in the RCS file */
fprintf (fprcs, "comment @%s@;\n\n", get_comment (user)) == EOF)
{
goto write_error;
}
/*
* puttree()
*/
(void) time (&now);
#ifdef HAVE_RCS5
ftm = gmtime (&now);
#else
ftm = localtime (&now);
#endif
(void) sprintf (altdate1, DATEFORM,
ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
ftm->tm_min, ftm->tm_sec);
now++;
#ifdef HAVE_RCS5
ftm = gmtime (&now);
#else
ftm = localtime (&now);
#endif
(void) sprintf (altdate2, DATEFORM,
ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
ftm->tm_min, ftm->tm_sec);
author = getcaller ();
if (fprintf (fprcs, "\n%s\n", vhead) == EOF ||
fprintf (fprcs, "date %s; author %s; state Exp;\n",
altdate1, author) == EOF ||
fprintf (fprcs, "branches %s.1;\n", vbranch) == EOF ||
fprintf (fprcs, "next ;\n") == EOF ||
fprintf (fprcs, "\n%s.1\n", vbranch) == EOF ||
fprintf (fprcs, "date %s; author %s; state Exp;\n",
altdate2, author) == EOF ||
fprintf (fprcs, "branches ;\n") == EOF ||
fprintf (fprcs, "next ;\n\n") == EOF ||
/*
* putdesc()
*/
fprintf (fprcs, "\ndesc\n") == EOF ||
fprintf (fprcs, "@@\n\n\n") == EOF ||
/*
* putdelta()
*/
fprintf (fprcs, "\n%s\n", vhead) == EOF ||
fprintf (fprcs, "log\n") == EOF ||
fprintf (fprcs, "@Initial revision\n@\n") == EOF ||
fprintf (fprcs, "text\n@") == EOF)
{
goto write_error;
}
if (fstat (fileno (fpuser), &sb) < 0)
error (1, errno, "cannot fstat %s", user);
if (sb.st_size > 0)
{
off_t size;
size = sb.st_size;
buf = xmalloc ((int) size);
if (fread (buf, (int) size, 1, fpuser) != 1)
error (1, errno, "cannot read file %s for copying", user);
if (expand_at_signs (buf, size, fprcs) == EOF)
goto write_error;
free (buf);
}
if (fprintf (fprcs, "@\n\n") == EOF ||
fprintf (fprcs, "\n%s.1\n", vbranch) == EOF ||
fprintf (fprcs, "log\n@") == EOF ||
expand_at_signs (message, (off_t) strlen (message), fprcs) == EOF ||
fprintf (fprcs, "@\ntext\n") == EOF ||
fprintf (fprcs, "@@\n") == EOF)
{
goto write_error;
}
if (fclose (fprcs) == EOF)
{
ierrno = errno;
goto write_error_noclose;
}
(void) fclose (fpuser);
/*
* Fix the modes on the RCS files. They must maintain the same modes as
* the original user file, except that all write permissions must be
* turned off.
*/
mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH);
if (chmod (rcs, mode) < 0)
{
ierrno = errno;
fperror (logfp, 0, ierrno,
"WARNING: cannot change mode of file %s", rcs);
error (0, ierrno, "WARNING: cannot change mode of file %s", rcs);
err++;
}
return (err);
write_error:
ierrno = errno;
(void) fclose (fprcs);
write_error_noclose:
(void) fclose (fpuser);
fperror (logfp, 0, ierrno, "ERROR: cannot write file %s", rcs);
error (0, ierrno, "ERROR: cannot write file %s", rcs);
if (ierrno == ENOSPC)
{
(void) unlink (rcs);
fperror (logfp, 0, 0, "ERROR: out of space - aborting");
error (1, 0, "ERROR: out of space - aborting");
}
return (err + 1);
}
/*
* Sigh.. need to expand @ signs into double @ signs
*/
static int
expand_at_signs (buf, size, fp)
char *buf;
off_t size;
FILE *fp;
{
char *cp, *end;
for (cp = buf, end = buf + size; cp < end; cp++)
{
if (*cp == '@')
(void) putc ('@', fp);
if (putc (*cp, fp) == EOF)
return (EOF);
}
return (1);
}
/*
* Write an update message to (potentially) the screen and the log file.
*/
static void
add_log (ch, fname)
char ch;
char *fname;
{
if (!really_quiet) /* write to terminal */
{
if (repos_len)
(void) printf ("%c %s/%s\n", ch, repository + repos_len + 1, fname);
else if (repository[0])
(void) printf ("%c %s/%s\n", ch, repository, fname);
else
(void) printf ("%c %s\n", ch, fname);
}
if (repos_len) /* write to logfile */
(void) fprintf (logfp, "%c %s/%s\n", ch,
repository + repos_len + 1, fname);
else if (repository[0])
(void) fprintf (logfp, "%c %s/%s\n", ch, repository, fname);
else
(void) fprintf (logfp, "%c %s\n", ch, fname);
}
/*
* This is the recursive function that walks the argument directory looking
* for sub-directories that have CVS administration files in them and updates
* them recursively.
*
* Note that we do not follow symbolic links here, which is a feature!
*/
static int
import_descend_dir (message, dir, vtag, targc, targv)
char *message;
char *dir;
char *vtag;
int targc;
char *targv[];
{
char cwd[PATH_MAX];
char *cp;
int ierrno, err;
if (islink (dir))
return (0);
if (getwd (cwd) == NULL)
{
fperror (logfp, 0, 0, "ERROR: cannot get working directory: %s", cwd);
error (0, 0, "ERROR: cannot get working directory: %s", cwd);
return (1);
}
if (repository[0] == '\0')
(void) strcpy (repository, dir);
else
{
(void) strcat (repository, "/");
(void) strcat (repository, dir);
}
if (!quiet)
error (0, 0, "Importing %s", repository);
if (chdir (dir) < 0)
{
ierrno = errno;
fperror (logfp, 0, ierrno, "ERROR: cannot chdir to %s", repository);
error (0, ierrno, "ERROR: cannot chdir to %s", repository);
err = 1;
goto out;
}
if (!isdir (repository))
{
if (isfile (repository))
{
fperror (logfp, 0, 0, "ERROR: %s is a file, should be a directory!",
repository);
error (0, 0, "ERROR: %s is a file, should be a directory!",
repository);
err = 1;
goto out;
}
if (noexec == 0 && mkdir (repository, 0777) < 0)
{
ierrno = errno;
fperror (logfp, 0, ierrno,
"ERROR: cannot mkdir %s -- not added", repository);
error (0, ierrno,
"ERROR: cannot mkdir %s -- not added", repository);
err = 1;
goto out;
}
}
err = import_descend (message, vtag, targc, targv);
out:
if ((cp = rindex (repository, '/')) != NULL)
*cp = '\0';
else
repository[0] = '\0';
if (chdir (cwd) < 0)
error (1, errno, "cannot chdir to %s", cwd);
return (err);
}

522
gnu/usr.bin/cvs/cvs/lock.c Normal file
View File

@ -0,0 +1,522 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* Set Lock
*
* Lock file support for CVS.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)lock.c 1.42 92/04/10";
#endif
extern char *ctime ();
#if __STDC__
static int readers_exist (char *repository);
static int set_lock (char *lockdir, int will_wait, char *repository);
static void set_lockers_name (struct stat *statp);
static int set_writelock_proc (Node * p);
static int unlock_proc (Node * p);
static int write_lock (char *repository);
static void unlock (char *repository);
static void lock_wait ();
#else
static int unlock_proc ();
static void unlock ();
static int set_writelock_proc ();
static int write_lock ();
static int readers_exist ();
static int set_lock ();
static void set_lockers_name ();
static void lock_wait ();
#endif /* __STDC__ */
static char lockers_name[20];
static char *repository;
static char readlock[PATH_MAX], writelock[PATH_MAX];
static int cleanup_lckdir;
static List *locklist;
#define L_OK 0 /* success */
#define L_ERROR 1 /* error condition */
#define L_LOCK_OWNED 2 /* lock already owned by us */
#define L_LOCKED 3 /* lock owned by someone else */
/*
* Clean up all outstanding locks
*/
void
Lock_Cleanup ()
{
/* clean up simple locks (if any) */
if (repository != NULL)
{
unlock (repository);
repository = (char *) NULL;
}
/* clean up multiple locks (if any) */
if (locklist != (List *) NULL)
{
(void) walklist (locklist, unlock_proc);
locklist = (List *) NULL;
}
}
/*
* walklist proc for removing a list of locks
*/
static int
unlock_proc (p)
Node *p;
{
unlock (p->key);
return (0);
}
/*
* Remove the lock files (without complaining if they are not there),
*/
static void
unlock (repository)
char *repository;
{
char tmp[PATH_MAX];
struct stat sb;
if (readlock[0] != '\0')
{
(void) sprintf (tmp, "%s/%s", repository, readlock);
(void) unlink (tmp);
}
if (writelock[0] != '\0')
{
(void) sprintf (tmp, "%s/%s", repository, writelock);
(void) unlink (tmp);
}
/*
* Only remove the lock directory if it is ours, note that this does
* lead to the limitation that one user ID should not be committing
* files into the same Repository directory at the same time. Oh well.
*/
(void) sprintf (tmp, "%s/%s", repository, CVSLCK);
if (stat (tmp, &sb) != -1 && sb.st_uid == geteuid () &&
(writelock[0] != '\0' || (readlock[0] != '\0' && cleanup_lckdir)))
{
(void) rmdir (tmp);
}
cleanup_lckdir = 0;
}
/*
* Create a lock file for readers
*/
int
Reader_Lock (xrepository)
char *xrepository;
{
int err = 0;
FILE *fp;
char tmp[PATH_MAX];
if (noexec)
return (0);
/* we only do one directory at a time for read locks! */
if (repository != NULL)
{
error (0, 0, "Reader_Lock called while read locks set - Help!");
return (1);
}
if (readlock[0] == '\0')
(void) sprintf (readlock, "%s.%d", CVSRFL, getpid ());
/* remember what we're locking (for lock_cleanup) */
repository = xrepository;
/* make sure we clean up on error */
(void) SIG_register (SIGHUP, Lock_Cleanup);
(void) SIG_register (SIGINT, Lock_Cleanup);
(void) SIG_register (SIGQUIT, Lock_Cleanup);
(void) SIG_register (SIGPIPE, Lock_Cleanup);
(void) SIG_register (SIGTERM, Lock_Cleanup);
/* make sure we can write the repository */
(void) sprintf (tmp, "%s/%s.%d", xrepository, CVSTFL, getpid ());
if ((fp = fopen (tmp, "w+")) == NULL || fclose (fp) == EOF)
{
error (0, errno, "cannot create read lock in repository `%s'",
xrepository);
readlock[0] = '\0';
(void) unlink (tmp);
return (1);
}
(void) unlink (tmp);
/* get the lock dir for our own */
(void) sprintf (tmp, "%s/%s", xrepository, CVSLCK);
if (set_lock (tmp, 1, xrepository) != L_OK)
{
error (0, 0, "failed to obtain dir lock in repository `%s'",
xrepository);
readlock[0] = '\0';
return (1);
}
/* write a read-lock */
(void) sprintf (tmp, "%s/%s", xrepository, readlock);
if ((fp = fopen (tmp, "w+")) == NULL || fclose (fp) == EOF)
{
error (0, errno, "cannot create read lock in repository `%s'",
xrepository);
readlock[0] = '\0';
err = 1;
}
/* free the lock dir */
(void) sprintf (tmp, "%s/%s", xrepository, CVSLCK);
if (rmdir (tmp) < 0)
error (0, errno, "failed to remove lock dir `%s'", tmp);
return (err);
}
/*
* Lock a list of directories for writing
*/
static char *lock_error_repos;
static int lock_error;
int
Writer_Lock (list)
List *list;
{
if (noexec)
return (0);
/* We only know how to do one list at a time */
if (locklist != (List *) NULL)
{
error (0, 0, "Writer_Lock called while write locks set - Help!");
return (1);
}
for (;;)
{
/* try to lock everything on the list */
lock_error = L_OK; /* init for set_writelock_proc */
lock_error_repos = (char *) NULL; /* init for set_writelock_proc */
locklist = list; /* init for Lock_Cleanup */
(void) strcpy (lockers_name, "unknown");
(void) walklist (list, set_writelock_proc);
switch (lock_error)
{
case L_ERROR: /* Real Error */
Lock_Cleanup (); /* clean up any locks we set */
error (0, 0, "lock failed - giving up");
return (1);
case L_LOCKED: /* Someone already had a lock */
Lock_Cleanup (); /* clean up any locks we set */
lock_wait (lock_error_repos); /* sleep a while and try again */
continue;
case L_OK: /* we got the locks set */
return (0);
default:
error (0, 0, "unknown lock status %d in Writer_Lock",
lock_error);
return (1);
}
}
}
/*
* walklist proc for setting write locks
*/
static int
set_writelock_proc (p)
Node *p;
{
/* if some lock was not OK, just skip this one */
if (lock_error != L_OK)
return (0);
/* apply the write lock */
lock_error_repos = p->key;
lock_error = write_lock (p->key);
return (0);
}
/*
* Create a lock file for writers returns L_OK if lock set ok, L_LOCKED if
* lock held by someone else or L_ERROR if an error occurred
*/
static int
write_lock (repository)
char *repository;
{
int status;
FILE *fp;
char tmp[PATH_MAX];
if (writelock[0] == '\0')
(void) sprintf (writelock, "%s.%d", CVSWFL, getpid ());
/* make sure we clean up on error */
(void) SIG_register (SIGHUP, Lock_Cleanup);
(void) SIG_register (SIGINT, Lock_Cleanup);
(void) SIG_register (SIGQUIT, Lock_Cleanup);
(void) SIG_register (SIGPIPE, Lock_Cleanup);
(void) SIG_register (SIGTERM, Lock_Cleanup);
/* make sure we can write the repository */
(void) sprintf (tmp, "%s/%s.%d", repository, CVSTFL, getpid ());
if ((fp = fopen (tmp, "w+")) == NULL || fclose (fp) == EOF)
{
error (0, errno, "cannot create write lock in repository `%s'",
repository);
(void) unlink (tmp);
return (L_ERROR);
}
(void) unlink (tmp);
/* make sure the lock dir is ours (not necessarily unique to us!) */
(void) sprintf (tmp, "%s/%s", repository, CVSLCK);
status = set_lock (tmp, 0, repository);
if (status == L_OK || status == L_LOCK_OWNED)
{
/* we now own a writer - make sure there are no readers */
if (readers_exist (repository))
{
/* clean up the lock dir if we created it */
if (status == L_OK)
{
if (rmdir (tmp) < 0)
error (0, errno, "failed to remove lock dir `%s'", tmp);
}
/* indicate we failed due to read locks instead of error */
return (L_LOCKED);
}
/* write the write-lock file */
(void) sprintf (tmp, "%s/%s", repository, writelock);
if ((fp = fopen (tmp, "w+")) == NULL || fclose (fp) == EOF)
{
int xerrno = errno;
(void) unlink (tmp);
/* free the lock dir if we created it */
if (status == L_OK)
{
(void) sprintf (tmp, "%s/%s", repository, CVSLCK);
if (rmdir (tmp) < 0)
error (0, errno, "failed to remove lock dir `%s'", tmp);
}
/* return the error */
error (0, xerrno, "cannot create write lock in repository `%s'",
repository);
return (L_ERROR);
}
return (L_OK);
}
else
return (status);
}
/*
* readers_exist() returns 0 if there are no reader lock files remaining in
* the repository; else 1 is returned, to indicate that the caller should
* sleep a while and try again.
*/
static int
readers_exist (repository)
char *repository;
{
char line[MAXLINELEN];
DIR *dirp;
struct direct *dp;
struct stat sb;
CONST char *regex_err;
int ret = 0;
#ifdef CVS_FUDGELOCKS
again:
#endif
if ((dirp = opendir (repository)) == NULL)
error (1, 0, "cannot open directory %s", repository);
(void) sprintf (line, "^%s.*", CVSRFL);
if ((regex_err = re_comp (line)) != NULL)
error (1, 0, "%s", regex_err);
while ((dp = readdir (dirp)) != NULL)
{
(void) sprintf (line, "%s/%s", repository, dp->d_name);
if (re_exec (dp->d_name))
{
#ifdef CVS_FUDGELOCKS
time_t now;
(void) time (&now);
/*
* If the create time of the file is more than CVSLCKAGE seconds
* ago, try to clean-up the lock file, and if successful, re-open
* the directory and try again.
*/
if (stat (line, &sb) != -1)
{
if (now >= (sb.st_ctime + CVSLCKAGE) && unlink (line) != -1)
{
(void) closedir (dirp);
goto again;
}
set_lockers_name (&sb);
}
#else
if (stat (line, &sb) != -1)
set_lockers_name (&sb);
#endif
ret = 1;
break;
}
}
(void) closedir (dirp);
return (ret);
}
/*
* Set the static variable lockers_name appropriately, based on the stat
* structure passed in.
*/
static void
set_lockers_name (statp)
struct stat *statp;
{
struct passwd *pw;
if ((pw = (struct passwd *) getpwuid (statp->st_uid)) !=
(struct passwd *) NULL)
{
(void) strcpy (lockers_name, pw->pw_name);
}
else
(void) sprintf (lockers_name, "uid%d", statp->st_uid);
}
/*
* Persistently tries to make the directory "lckdir",, which serves as a
* lock. If the create time on the directory is greater than CVSLCKAGE
* seconds old, just try to remove the directory.
*/
static int
set_lock (lockdir, will_wait, repository)
char *lockdir;
int will_wait;
char *repository;
{
struct stat sb;
#ifdef CVS_FUDGELOCKS
time_t now;
#endif
/*
* Note that it is up to the callers of set_lock() to arrange for signal
* handlers that do the appropriate things, like remove the lock
* directory before they exit.
*/
cleanup_lckdir = 0;
for (;;)
{
SIG_beginCrSect ();
if (mkdir (lockdir, 0777) == 0)
{
cleanup_lckdir = 1;
SIG_endCrSect ();
return (L_OK);
}
SIG_endCrSect ();
if (errno != EEXIST)
{
error (0, errno,
"failed to create lock directory in repository `%s'",
repository);
return (L_ERROR);
}
/*
* stat the dir - if it is non-existent, re-try the loop since
* someone probably just removed it (thus releasing the lock)
*/
if (stat (lockdir, &sb) < 0)
{
if (errno == ENOENT)
continue;
error (0, errno, "couldn't stat lock directory `%s'", lockdir);
return (L_ERROR);
}
/*
* if we already own the lock, go ahead and return 1 which means it
* existed but we owned it
*/
if (sb.st_uid == geteuid () && !will_wait)
return (L_LOCK_OWNED);
#ifdef CVS_FUDGELOCKS
/*
* If the create time of the directory is more than CVSLCKAGE seconds
* ago, try to clean-up the lock directory, and if successful, just
* quietly retry to make it.
*/
(void) time (&now);
if (now >= (sb.st_ctime + CVSLCKAGE))
{
if (rmdir (lockdir) >= 0)
continue;
}
#endif
/* set the lockers name */
set_lockers_name (&sb);
/* if he wasn't willing to wait, return an error */
if (!will_wait)
return (L_LOCKED);
lock_wait (repository);
}
}
/*
* Print out a message that the lock is still held, then sleep a while.
*/
static void
lock_wait (repos)
char *repos;
{
time_t now;
(void) time (&now);
error (0, 0, "[%8.8s] waiting for %s's lock in %s", ctime (&now) + 11,
lockers_name, repos);
(void) sleep (CVSLCKSLEEP);
}

132
gnu/usr.bin/cvs/cvs/log.c Normal file
View File

@ -0,0 +1,132 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* Print Log Information
*
* Prints the RCS "log" (rlog) information for the specified files. With no
* argument, prints the log information for all the files in the directory
* (recursive by default).
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)log.c 1.39 92/03/31";
#endif
#if __STDC__
static Dtype log_dirproc (char *dir, char *repository, char *update_dir);
static int log_fileproc (char *file, char *update_dir, char *repository,
List * entries, List * srcfiles);
#else
static int log_fileproc ();
static Dtype log_dirproc ();
#endif /* __STDC__ */
static char options[PATH_MAX];
static char *log_usage[] =
{
"Usage: %s %s [-l] [rlog-options] [files...]\n",
"\t-l\tLocal directory only, no recursion.\n",
NULL
};
int
cvslog (argc, argv)
int argc;
char *argv[];
{
int i;
int numopt = 1;
int err = 0;
int local = 0;
if (argc == -1)
usage (log_usage);
/*
* All 'log' command options except -l are passed directly on to 'rlog'
*/
options[0] = '\0'; /* Assume none */
for (i = 1; i < argc; i++)
{
if (argv[i][0] == '-' || argv[i][0] == '\0')
{
numopt++;
switch (argv[i][1])
{
case 'l':
local = 1;
break;
default:
(void) strcat (options, " ");
(void) strcat (options, argv[i]);
break;
}
}
}
argc -= numopt;
argv += numopt;
err = start_recursion (log_fileproc, (int (*) ()) NULL, log_dirproc,
(int (*) ()) NULL, argc, argv, local,
W_LOCAL | W_REPOS | W_ATTIC, 0, 1,
(char *) NULL, 1);
return (err);
}
/*
* Do an rlog on a file
*/
/* ARGSUSED */
static int
log_fileproc (file, update_dir, repository, entries, srcfiles)
char *file;
char *update_dir;
char *repository;
List *entries;
List *srcfiles;
{
Node *p;
RCSNode *rcsfile;
int retcode = 0;
p = findnode (srcfiles, file);
if (p == NULL || (rcsfile = (RCSNode *) p->data) == NULL)
{
if (!really_quiet)
error (0, 0, "nothing known about %s", file);
return (1);
}
run_setup ("%s%s %s", Rcsbin, RCS_RLOG, options);
run_arg (rcsfile->path);
if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_REALLY)) == -1)
{
error (1, errno, "fork failed for rlog on %s", file);
}
return (retcode);
}
/*
* Print a warm fuzzy message
*/
/* ARGSUSED */
static Dtype
log_dirproc (dir, repository, update_dir)
char *dir;
char *repository;
char *update_dir;
{
if (!isdir (dir))
return (R_SKIP_ALL);
if (!quiet)
error (0, 0, "Logging %s", update_dir);
return (R_PROCESS);
}

View File

@ -0,0 +1,449 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)logmsg.c 1.40 92/04/10";
#endif
#if __STDC__
static int find_type (Node * p);
static int fmt_proc (Node * p);
static int logfile_write (char *repository, char *filter, char *title,
char *message, char *revision, FILE * logfp,
List * changes);
static int rcsinfo_proc (char *repository, char *template);
static int title_proc (Node * p);
static int update_logfile_proc (char *repository, char *filter);
static void setup_tmpfile (FILE * xfp, char *xprefix, List * changes);
static int editinfo_proc (char *repository, char *template);
#else
static void setup_tmpfile ();
static int find_type ();
static int fmt_proc ();
static int rcsinfo_proc ();
static int update_logfile_proc ();
static int title_proc ();
static int logfile_write ();
static int editinfo_proc ();
#endif /* __STDC__ */
static FILE *fp;
static char *strlist;
static char *editinfo_editor;
static Ctype type;
/*
* Puts a standard header on the output which is either being prepared for an
* editor session, or being sent to a logfile program. The modified, added,
* and removed files are included (if any) and formatted to look pretty.
*/
static char *prefix;
static int col;
static void
setup_tmpfile (xfp, xprefix, changes)
FILE *xfp;
char *xprefix;
List *changes;
{
/* set up statics */
fp = xfp;
prefix = xprefix;
type = T_MODIFIED;
if (walklist (changes, find_type) != 0)
{
(void) fprintf (fp, "%sModified Files:\n", prefix);
(void) fprintf (fp, "%s\t", prefix);
col = 8;
(void) walklist (changes, fmt_proc);
(void) fprintf (fp, "\n");
}
type = T_ADDED;
if (walklist (changes, find_type) != 0)
{
(void) fprintf (fp, "%sAdded Files:\n", prefix);
(void) fprintf (fp, "%s\t", prefix);
col = 8;
(void) walklist (changes, fmt_proc);
(void) fprintf (fp, "\n");
}
type = T_REMOVED;
if (walklist (changes, find_type) != 0)
{
(void) fprintf (fp, "%sRemoved Files:\n", prefix);
(void) fprintf (fp, "%s\t", prefix);
col = 8;
(void) walklist (changes, fmt_proc);
(void) fprintf (fp, "\n");
}
}
/*
* Looks for nodes of a specified type and returns 1 if found
*/
static int
find_type (p)
Node *p;
{
if (p->data == (char *) type)
return (1);
else
return (0);
}
/*
* Breaks the files list into reasonable sized lines to avoid line wrap...
* all in the name of pretty output. It only works on nodes whose types
* match the one we're looking for
*/
static int
fmt_proc (p)
Node *p;
{
if (p->data == (char *) type)
{
if ((col + (int) strlen (p->key)) > 70)
{
(void) fprintf (fp, "\n%s\t", prefix);
col = 8;
}
(void) fprintf (fp, "%s ", p->key);
col += strlen (p->key) + 1;
}
return (0);
}
/*
* Builds a temporary file using setup_tmpfile() and invokes the user's
* editor on the file. The header garbage in the resultant file is then
* stripped and the log message is stored in the "message" argument.
*
* rcsinfo - is the name of a file containing lines tacked onto the end of the
* RCS info offered to the user for editing. If specified, the '-m' flag to
* "commit" is disabled -- users are forced to run the editor.
*
*/
void
do_editor (dir, message, repository, changes)
char *dir;
char *message;
char *repository;
List *changes;
{
static int reuse_log_message = 0;
char line[MAXLINELEN], fname[L_tmpnam+1];
char *orig_message;
struct stat pre_stbuf, post_stbuf;
int retcode = 0;
if (noexec || reuse_log_message)
return;
orig_message = xstrdup (message); /* save it for later */
/* Create a temporary file */
(void) tmpnam (fname);
again:
if ((fp = fopen (fname, "w+")) == NULL)
error (1, 0, "cannot create temporary file %s", fname);
/* set up the file so that the first line is blank if no msg specified */
if (*orig_message)
{
(void) fprintf (fp, "%s", orig_message);
if (orig_message[strlen (orig_message) - 1] != '\n')
(void) fprintf (fp, "\n");
}
else
(void) fprintf (fp, "\n");
/* tack templates on if necessary */
(void) Parse_Info (CVSROOTADM_RCSINFO, repository, rcsinfo_proc, 1);
(void) fprintf (fp,
"%s----------------------------------------------------------------------\n",
CVSEDITPREFIX);
(void) fprintf (fp,
"%sEnter Log. Lines beginning with `%s' are removed automatically\n%s\n",
CVSEDITPREFIX, CVSEDITPREFIX, CVSEDITPREFIX);
if (dir != NULL)
(void) fprintf (fp, "%sCommitting in %s\n%s\n", CVSEDITPREFIX,
dir, CVSEDITPREFIX);
setup_tmpfile (fp, CVSEDITPREFIX, changes);
(void) fprintf (fp,
"%s----------------------------------------------------------------------\n",
CVSEDITPREFIX);
/* finish off the temp file */
(void) fclose (fp);
if (stat (fname, &pre_stbuf) == -1)
pre_stbuf.st_mtime = 0;
if (editinfo_editor)
free (editinfo_editor);
editinfo_editor = (char *) NULL;
(void) Parse_Info (CVSROOTADM_EDITINFO, repository, editinfo_proc, 0);
/* run the editor */
run_setup ("%s", editinfo_editor ? editinfo_editor : Editor);
run_arg (fname);
if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
RUN_NORMAL | RUN_SIGIGNORE)) != 0)
error (editinfo_editor ? 1 : 0, retcode == -1 ? errno : 0,
editinfo_editor ? "Logfile verification failed" :
"warning: editor session failed");
/* put the entire message back into the message variable */
fp = open_file (fname, "r");
*message = '\0';
while (fgets (line, sizeof (line), fp) != NULL)
{
if (strncmp (line, CVSEDITPREFIX, sizeof (CVSEDITPREFIX) - 1) == 0)
continue;
if (((int) strlen (message) + (int) strlen (line)) >= MAXMESGLEN)
{
error (0, 0, "warning: log message truncated!");
break;
}
(void) strcat (message, line);
}
(void) fclose (fp);
if ((stat (fname, &post_stbuf) == 0 &&
pre_stbuf.st_mtime == post_stbuf.st_mtime) ||
(*message == '\0' || strcmp (message, "\n") == 0))
{
for (;;)
{
(void) printf ("\nLog message unchanged or not specified\n");
(void) printf ("a)bort, c)continue, e)dit, !)reuse this message unchanged for remaining dirs\n");
(void) printf ("Action: (continue) ");
(void) fflush (stdout);
*line = '\0';
(void) fgets (line, sizeof (line), stdin);
if (*line == '\0' || *line == '\n' || *line == 'c' || *line == 'C')
break;
if (*line == 'a' || *line == 'A')
error (1, 0, "aborted by user");
if (*line == 'e' || *line == 'E')
goto again;
if (*line == '!')
{
reuse_log_message = 1;
break;
}
(void) printf ("Unknown input\n");
}
}
free (orig_message);
(void) unlink_file (fname);
}
/*
* callback proc for Parse_Info for rcsinfo templates this routine basically
* copies the matching template onto the end of the tempfile we are setting
* up
*/
/* ARGSUSED */
static int
rcsinfo_proc (repository, template)
char *repository;
char *template;
{
static char *last_template;
FILE *tfp;
char line[MAXLINELEN];
/* nothing to do if the last one included is the same as this one */
if (last_template && strcmp (last_template, template) == 0)
return (0);
if (last_template)
free (last_template);
last_template = xstrdup (template);
if ((tfp = fopen (template, "r")) != NULL)
{
while (fgets (line, sizeof (line), tfp) != NULL)
(void) fputs (line, fp);
(void) fclose (tfp);
return (0);
}
else
{
error (0, 0, "Couldn't open rcsinfo template file %s", template);
return (1);
}
}
/*
* Uses setup_tmpfile() to pass the updated message on directly to any
* logfile programs that have a regular expression match for the checked in
* directory in the source repository. The log information is fed into the
* specified program as standard input.
*/
static char *title;
static FILE *logfp;
static char *message;
static char *revision;
static List *changes;
void
Update_Logfile (repository, xmessage, xrevision, xlogfp, xchanges)
char *repository;
char *xmessage;
char *xrevision;
FILE *xlogfp;
List *xchanges;
{
char *srepos;
/* set up static vars for update_logfile_proc */
message = xmessage;
revision = xrevision;
logfp = xlogfp;
changes = xchanges;
/* figure out a good title string */
srepos = Short_Repository (repository);
/* allocate a chunk of memory to hold the title string */
if (!strlist)
strlist = xmalloc (MAXLISTLEN);
strlist[0] = '\0';
type = T_TITLE;
(void) walklist (changes, title_proc);
type = T_ADDED;
(void) walklist (changes, title_proc);
type = T_MODIFIED;
(void) walklist (changes, title_proc);
type = T_REMOVED;
(void) walklist (changes, title_proc);
title = xmalloc (strlen (srepos) + strlen (strlist) + 1 + 2); /* for 's */
(void) sprintf (title, "'%s%s'", srepos, strlist);
/* to be nice, free up this chunk of memory */
free (strlist);
strlist = (char *) NULL;
/* call Parse_Info to do the actual logfile updates */
(void) Parse_Info (CVSROOTADM_LOGINFO, repository, update_logfile_proc, 1);
/* clean up */
free (title);
}
/*
* callback proc to actually do the logfile write from Update_Logfile
*/
static int
update_logfile_proc (repository, filter)
char *repository;
char *filter;
{
return (logfile_write (repository, filter, title, message, revision,
logfp, changes));
}
/*
* concatenate each name onto strlist
*/
static int
title_proc (p)
Node *p;
{
if (p->data == (char *) type)
{
(void) strcat (strlist, " ");
(void) strcat (strlist, p->key);
}
return (0);
}
/*
* Since some systems don't define this...
*/
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 256
#endif
/*
* Writes some stuff to the logfile "filter" and returns the status of the
* filter program.
*/
static int
logfile_write (repository, filter, title, message, revision, logfp, changes)
char *repository;
char *filter;
char *title;
char *message;
char *revision;
FILE *logfp;
List *changes;
{
char cwd[PATH_MAX], host[MAXHOSTNAMELEN];
FILE *pipefp, *Popen ();
char *prog = xmalloc (MAXPROGLEN);
char *cp;
int c;
/*
* A maximum of 6 %s arguments are supported in the filter
*/
(void) sprintf (prog, filter, title, title, title, title, title, title);
if ((pipefp = Popen (prog, "w")) == NULL)
{
if (!noexec)
error (0, 0, "cannot write entry to log filter: %s", prog);
free (prog);
return (1);
}
if (gethostname (host, sizeof (host)) < 0)
(void) strcpy (host, "(unknown)");
(void) fprintf (pipefp, "Update of %s\n", repository);
(void) fprintf (pipefp, "In directory %s:%s\n\n", host,
((cp = getwd (cwd)) != NULL) ? cp : cwd);
if (revision && *revision)
(void) fprintf (pipefp, "Revision/Branch: %s\n\n", revision);
setup_tmpfile (pipefp, "", changes);
(void) fprintf (pipefp, "Log Message:\n%s\n", message);
if (logfp != (FILE *) 0)
{
(void) fprintf (pipefp, "Status:\n");
(void) rewind (logfp);
while ((c = getc (logfp)) != EOF)
(void) putc ((char) c, pipefp);
}
free (prog);
return (pclose (pipefp));
}
/*
* We choose to use the *last* match within the editinfo file for this
* repository. This allows us to have a global editinfo program for the
* root of some hierarchy, for example, and different ones within different
* sub-directories of the root (like a special checker for changes made to
* the "src" directory versus changes made to the "doc" or "test"
* directories.
*/
/* ARGSUSED */
static int
editinfo_proc(repository, editor)
char *repository;
char *editor;
{
/* nothing to do if the last match is the same as this one */
if (editinfo_editor && strcmp (editinfo_editor, editor) == 0)
return (0);
if (editinfo_editor)
free (editinfo_editor);
editinfo_editor = xstrdup (editor);
return (0);
}

444
gnu/usr.bin/cvs/cvs/main.c Normal file
View File

@ -0,0 +1,444 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License
* as specified in the README file that comes with the CVS 1.3 kit.
*
* This is the main C driver for the CVS system.
*
* Credit to Dick Grune, Vrije Universiteit, Amsterdam, for writing
* the shell-script CVS system that this is based on.
*
* Usage:
* cvs [options] command [options] [files/modules...]
*
* Where "command" is composed of:
* admin RCS command
* checkout Check out a module/dir/file
* export Like checkout, but used for exporting sources
* update Brings work tree in sync with repository
* commit Checks files into the repository
* diff Runs diffs between revisions
* log Prints "rlog" information for files
* add Adds an entry to the repository
* remove Removes an entry from the repository
* status Status info on the revisions
* rdiff "patch" format diff listing between releases
* tag Add/delete a symbolic tag to the RCS file
* rtag Add/delete a symbolic tag to the RCS file
* import Import sources into CVS, using vendor branches
* release Indicate that Module is no longer in use.
* history Display history of Users and Modules.
*/
#include "cvs.h"
#include "patchlevel.h"
char rcsid[] = "@(#)main.c 1.64 92/03/31\n";
extern char *getenv ();
char *program_name;
char *command_name = "";
int use_editor = TRUE;
int cvswrite = !CVSREAD_DFLT;
int really_quiet = FALSE;
int quiet = FALSE;
int trace = FALSE;
int noexec = FALSE;
int logoff = FALSE;
char *CurDir;
/*
* Defaults, for the environment variables that are not set
*/
char *Rcsbin = RCSBIN_DFLT;
char *Editor = EDITOR_DFLT;
char *CVSroot = CVSROOT_DFLT;
#if __STDC__
int add (int argc, char **argv);
int admin (int argc, char **argv);
int checkout (int argc, char **argv);
int commit (int argc, char **argv);
int diff (int argc, char **argv);
int history (int argc, char **argv);
int import (int argc, char **argv);
int cvslog (int argc, char **argv);
int patch (int argc, char **argv);
int release (int argc, char **argv);
int cvsremove (int argc, char **argv);
int rtag (int argc, char **argv);
int status (int argc, char **argv);
int tag (int argc, char **argv);
int update (int argc, char **argv);
#else
int add ();
int admin ();
int checkout ();
int commit ();
int diff ();
int history ();
int import ();
int cvslog ();
int patch ();
int release ();
int cvsremove ();
int rtag ();
int status ();
int tag ();
int update ();
#endif /* __STDC__ */
struct cmd
{
char *fullname; /* Full name of the function (e.g. "commit") */
char *nick1; /* alternate name (e.g. "ci") */
char *nick2; /* another alternate names (e.g. "ci") */
int (*func) (); /* Function takes (argc, argv) arguments. */
} cmds[] =
{
{ "add", "ad", "new", add },
{ "admin", "adm", "rcs", admin },
{ "checkout", "co", "get", checkout },
{ "commit", "ci", "com", commit },
{ "diff", "di", "dif", diff },
{ "export", "exp", "ex", checkout },
{ "history", "hi", "his", history },
{ "import", "im", "imp", import },
{ "log", "lo", "rlog", cvslog },
{ "rdiff", "patch", "pa", patch },
{ "release", "re", "rel", release },
{ "remove", "rm", "delete", cvsremove },
{ "status", "st", "stat", status },
{ "rtag", "rt", "rfreeze", rtag },
{ "tag", "ta", "freeze", tag },
{ "update", "up", "upd", update },
{ NULL, NULL, NULL, NULL },
};
static char *usg[] =
{
"Usage: %s [cvs-options] command [command-options] [files...]\n",
" Where 'cvs-options' are:\n",
" -H Displays Usage information for command\n",
" -Q Cause CVS to be really quiet.\n",
" -q Cause CVS to be somewhat quiet.\n",
" -r Make checked-out files read-only\n",
" -w Make checked-out files read-write (default)\n",
" -l Turn History logging off\n",
" -n Do not execute anything that will change the disk\n",
" -t Show trace of program execution -- Try with -n\n",
" -v CVS version and copyright\n",
" -b bindir Find RCS programs in 'bindir'\n",
" -e editor Use 'editor' for editing log information\n",
" -d CVS_root Overrides $CVSROOT as the root of the CVS tree\n",
"\n",
" and where 'command' is:\n",
" add Adds a new file/directory to the repository\n",
" admin Administration front end for rcs\n",
" checkout Checkout sources for editing\n",
" commit Checks files into the repository\n",
" diff Runs diffs between revisions\n",
" history Shows status of files and users\n",
" import Import sources into CVS, using vendor branches\n",
" export Export sources from CVS, similar to checkout\n",
" log Prints out 'rlog' information for files\n",
" rdiff 'patch' format diffs between releases\n",
" release Indicate that a Module is no longer in use\n",
" remove Removes an entry from the repository\n",
" status Status info on the revisions\n",
" tag Add a symbolic tag to checked out version of RCS file\n",
" rtag Add a symbolic tag to the RCS file\n",
" update Brings work tree in sync with repository\n",
NULL,
};
static SIGTYPE
main_cleanup ()
{
exit (1);
}
int
main (argc, argv)
int argc;
char *argv[];
{
extern char *version_string;
char *cp;
struct cmd *cm;
int c, help = FALSE, err = 0;
int rcsbin_update_env, cvs_update_env;
char tmp[PATH_MAX];
/*
* Just save the last component of the path for error messages
*/
if ((program_name = rindex (argv[0], '/')) == NULL)
program_name = argv[0];
else
program_name++;
CurDir = xmalloc (PATH_MAX);
if (!getwd (CurDir))
error (1, 0, "cannot get working directory: %s", CurDir);
/*
* Query the environment variables up-front, so that
* they can be overridden by command line arguments
*/
rcsbin_update_env = *Rcsbin; /* RCSBIN_DFLT must be set */
if ((cp = getenv (RCSBIN_ENV)) != NULL)
{
Rcsbin = cp;
rcsbin_update_env = 0; /* it's already there */
}
if ((cp = getenv (EDITOR_ENV)) != NULL)
Editor = cp;
if ((cp = getenv (CVSROOT_ENV)) != NULL)
{
CVSroot = cp;
cvs_update_env = 0; /* it's already there */
}
if (getenv (CVSREAD_ENV) != NULL)
cvswrite = FALSE;
optind = 1;
while ((c = gnu_getopt (argc, argv, "Qqrwtnlvb:e:d:H")) != -1)
{
switch (c)
{
case 'Q':
really_quiet = TRUE;
/* FALL THROUGH */
case 'q':
quiet = TRUE;
break;
case 'r':
cvswrite = FALSE;
break;
case 'w':
cvswrite = TRUE;
break;
case 't':
trace = TRUE;
break;
case 'n':
noexec = TRUE;
case 'l': /* Fall through */
logoff = TRUE;
break;
case 'v':
(void) fputs (rcsid, stdout);
(void) fputs (version_string, stdout);
(void) sprintf (tmp, "Patch Level: %d\n", PATCHLEVEL);
(void) fputs (tmp, stdout);
(void) fputs ("\nCopyright (c) 1992, Brian Berliner and Jeff Polk\nCopyright (c) 1989-1992, Brian Berliner\n\nCVS may be copied only under the terms of the GNU General Public License,\na copy of which can be found with the CVS 1.3 distribution kit.\n", stdout);
exit (0);
break;
case 'b':
Rcsbin = optarg;
rcsbin_update_env = 1; /* need to update environment */
break;
case 'e':
Editor = optarg;
break;
case 'd':
CVSroot = optarg;
cvs_update_env = 1; /* need to update environment */
break;
case 'H':
help = TRUE;
break;
case '?':
default:
usage (usg);
}
}
argc -= optind;
argv += optind;
if (argc < 1)
usage (usg);
/*
* XXX - Compatibility. This can be removed in the release after CVS 1.3.
* Try to rename the CVSROOT.adm file to CVSROOT, unless there already is
* a CVSROOT directory.
*/
if (CVSroot != NULL)
{
char rootadm[PATH_MAX];
char orootadm[PATH_MAX];
(void) sprintf (rootadm, "%s/%s", CVSroot, CVSROOTADM);
if (!isdir (rootadm))
{
(void) sprintf (orootadm, "%s/%s", CVSroot, OCVSROOTADM);
if (isdir (orootadm))
(void) rename (orootadm, rootadm);
}
strip_path (CVSroot);
}
/*
* Specifying just the '-H' flag to the sub-command causes a Usage
* message to be displayed.
*/
command_name = cp = argv[0];
if (help == TRUE || (argc > 1 && strcmp (argv[1], "-H") == 0))
argc = -1;
else
{
/*
* Check to see if we can write into the history file. If not,
* we assume that we can't work in the repository.
* BUT, only if the history file exists.
*/
{
char path[PATH_MAX];
int save_errno;
if (!CVSroot || !*CVSroot)
error (1, 0, "You don't have a %s environment variable",
CVSROOT_ENV);
(void) sprintf (path, "%s/%s", CVSroot, CVSROOTADM);
if (access (path, R_OK | X_OK))
{
save_errno = errno;
error (0, 0,
"Sorry, you don't have sufficient access to %s", CVSroot);
error (1, save_errno, "%s", path);
}
(void) strcat (path, "/");
(void) strcat (path, CVSROOTADM_HISTORY);
if (isfile (path) && access (path, R_OK | W_OK))
{
save_errno = errno;
error (0, 0,
"Sorry, you don't have read/write access to the history file");
error (1, save_errno, "%s", path);
}
}
}
#ifndef PUTENV_MISSING
/* Now, see if we should update the environment with the Rcsbin value */
if (cvs_update_env)
{
char *env;
env = xmalloc (strlen (CVSROOT_ENV) + strlen (CVSroot) + 1 + 1);
(void) sprintf (env, "%s=%s", CVSROOT_ENV, CVSroot);
(void) putenv (env);
/* do not free env, as putenv has control of it */
}
if (rcsbin_update_env)
{
char *env;
env = xmalloc (strlen (RCSBIN_ENV) + strlen (Rcsbin) + 1 + 1);
(void) sprintf (env, "%s=%s", RCSBIN_ENV, Rcsbin);
(void) putenv (env);
/* do not free env, as putenv has control of it */
}
#endif
/*
* If Rcsbin is set to something, make sure it is terminated with
* a slash character. If not, add one.
*/
if (*Rcsbin)
{
int len = strlen (Rcsbin);
char *rcsbin;
if (Rcsbin[len - 1] != '/')
{
rcsbin = Rcsbin;
Rcsbin = xmalloc (len + 2); /* one for '/', one for NULL */
(void) strcpy (Rcsbin, rcsbin);
(void) strcat (Rcsbin, "/");
}
}
for (cm = cmds; cm->fullname; cm++)
{
if (cm->nick1 && !strcmp (cp, cm->nick1))
break;
if (cm->nick2 && !strcmp (cp, cm->nick2))
break;
if (!strcmp (cp, cm->fullname))
break;
}
if (!cm->fullname)
usage (usg); /* no match */
else
{
command_name = cm->fullname; /* Global pointer for later use */
(void) SIG_register (SIGHUP, main_cleanup);
(void) SIG_register (SIGINT, main_cleanup);
(void) SIG_register (SIGQUIT, main_cleanup);
(void) SIG_register (SIGPIPE, main_cleanup);
(void) SIG_register (SIGTERM, main_cleanup);
#ifndef SETVBUF_MISSING
/*
* Make stdout line buffered, so 'tail -f' can monitor progress.
* Patch creates too much output to monitor and it runs slowly.
*/
if (strcmp (cm->fullname, "patch"))
(void) setvbuf (stdout, (char *) NULL, _IOLBF, 0);
#endif
err = (*(cm->func)) (argc, argv);
}
/*
* If the command's error count is modulo 256, we need to change it
* so that we don't overflow the 8-bits we get to report exit status
*/
if (err && (err % 256) == 0)
err = 1;
Lock_Cleanup ();
return (err);
}
char *
Make_Date (rawdate)
char *rawdate;
{
struct tm *ftm;
time_t unixtime;
char date[256]; /* XXX bigger than we'll ever need? */
char *ret;
unixtime = get_date (rawdate, (struct timeb *) NULL);
if (unixtime == (time_t) - 1)
error (1, 0, "Can't parse date/time: %s", rawdate);
#ifdef HAVE_RCS5
ftm = gmtime (&unixtime);
#else
ftm = localtime (&unixtime);
#endif
(void) sprintf (date, DATEFORM,
ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
ftm->tm_min, ftm->tm_sec);
ret = xstrdup (date);
return (ret);
}
void
usage (cpp)
register char **cpp;
{
(void) fprintf (stderr, *cpp++, program_name, command_name);
for (; *cpp; cpp++)
(void) fprintf (stderr, *cpp);
exit (1);
}

View File

@ -0,0 +1,810 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License
* as specified in the README file that comes with the CVS 1.3 kit.
*
* Modules
*
* Functions for accessing the modules file.
*
* The modules file supports basically three formats of lines:
* key [options] directory files... [ -x directory [files] ] ...
* key [options] directory [ -x directory [files] ] ...
* key -a aliases...
*
* The -a option allows an aliasing step in the parsing of the modules
* file. The "aliases" listed on a line following the -a are
* processed one-by-one, as if they were specified as arguments on the
* command line.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)modules.c 1.57 92/04/10";
#endif
struct sortrec
{
char *modname;
char *status;
char *rest;
char *comment;
};
#if __STDC__
static int sort_order (CONST PTR l, CONST PTR r);
static void save_d (char *k, int ks, char *d, int ds);
#else
static int sort_order ();
static void save_d ();
#endif /* __STDC__ */
/*
* Open the modules file, and die if the CVSROOT environment variable
* was not set. If the modules file does not exist, that's fine, and
* a warning message is displayed and a NULL is returned.
*/
DBM *
open_module ()
{
char mfile[PATH_MAX];
if (CVSroot == NULL)
{
(void) fprintf (stderr,
"%s: must set the CVSROOT environment variable\n",
program_name);
error (1, 0, "or specify the '-d' option to %s", program_name);
}
(void) sprintf (mfile, "%s/%s/%s", CVSroot, CVSROOTADM, CVSROOTADM_MODULES);
return (dbm_open (mfile, O_RDONLY, 0666));
}
/*
* Close the modules file, if the open succeeded, that is
*/
void
close_module (db)
DBM *db;
{
if (db != NULL)
dbm_close (db);
}
/*
* This is the recursive function that processes a module name.
* It calls back the passed routine for each directory of a module
* It runs the post checkout or post tag proc from the modules file
*/
int
do_module (db, mname, m_type, msg, callback_proc, where,
shorten, local_specified, run_module_prog, extra_arg)
DBM *db;
char *mname;
enum mtype m_type;
char *msg;
int (*callback_proc) ();
char *where;
int shorten;
int local_specified;
int run_module_prog;
char *extra_arg;
{
char *checkin_prog = NULL;
char *checkout_prog = NULL;
char *tag_prog = NULL;
char *update_prog = NULL;
char cwd[PATH_MAX];
char line[MAXLINELEN];
char *xmodargv[MAXFILEPERDIR];
char **modargv;
char *value;
char *zvalue;
char *mwhere = NULL;
char *mfile = NULL;
char *spec_opt = NULL;
char xvalue[PATH_MAX];
int modargc, alias = 0;
datum key, val;
char *cp;
int c, err = 0;
/* remember where we start */
if (getwd (cwd) == NULL)
error (1, 0, "cannot get current working directory: %s", cwd);
/* strip extra stuff from the module name */
strip_path (mname);
/*
* Look up the module using the following scheme:
* 1) look for mname as a module name
* 2) look for mname as a directory
* 3) look for mname as a file
* 4) take mname up to the first slash and look it up as a module name
* (this is for checking out only part of a module)
*/
/* look it up as a module name */
key.dptr = mname;
key.dsize = strlen (key.dptr);
if (db != NULL)
val = dbm_fetch (db, key);
else
val.dptr = NULL;
if (val.dptr != NULL)
{
/* null terminate the value XXX - is this space ours? */
val.dptr[val.dsize] = '\0';
/* If the line ends in a comment, strip it off */
if ((cp = index (val.dptr, '#')) != NULL)
{
do
*cp-- = '\0';
while (isspace (*cp));
}
value = val.dptr;
mwhere = xstrdup (mname);
goto found;
}
else
{
char file[PATH_MAX];
char attic_file[PATH_MAX];
char *acp;
/* check to see if mname is a directory or file */
(void) sprintf (file, "%s/%s", CVSroot, mname);
if ((acp = rindex (mname, '/')) != NULL)
{
*acp = '\0';
(void) sprintf (attic_file, "%s/%s/%s/%s%s", CVSroot, mname,
CVSATTIC, acp + 1, RCSEXT);
*acp = '/';
}
else
(void) sprintf (attic_file, "%s/%s/%s%s", CVSroot, CVSATTIC,
mname, RCSEXT);
if (isdir (file))
{
value = mname;
goto found;
}
else
{
(void) strcat (file, RCSEXT);
if (isfile (file) || isfile (attic_file))
{
/* if mname was a file, we have to split it into "dir file" */
if ((cp = rindex (mname, '/')) != NULL && cp != mname)
{
char *slashp;
/* put the ' ' in a copy so we don't mess up the original */
value = strcpy (xvalue, mname);
slashp = rindex (value, '/');
*slashp = ' ';
}
else
{
/*
* the only '/' at the beginning or no '/' at all
* means the file we are interested in is in CVSROOT
* itself so the directory should be '.'
*/
if (cp == mname)
{
/* drop the leading / if specified */
value = strcpy (xvalue, ". ");
(void) strcat (xvalue, mname + 1);
}
else
{
/* otherwise just copy it */
value = strcpy (xvalue, ". ");
(void) strcat (xvalue, mname);
}
}
goto found;
}
}
}
/* look up everything to the first / as a module */
if (mname[0] != '/' && (cp = index (mname, '/')) != NULL)
{
/* Make the slash the new end of the string temporarily */
*cp = '\0';
key.dptr = mname;
key.dsize = strlen (key.dptr);
/* do the lookup */
if (db != NULL)
val = dbm_fetch (db, key);
else
val.dptr = NULL;
/* if we found it, clean up the value and life is good */
if (val.dptr != NULL)
{
char *cp2;
/* null terminate the value XXX - is this space ours? */
val.dptr[val.dsize] = '\0';
/* If the line ends in a comment, strip it off */
if ((cp2 = index (val.dptr, '#')) != NULL)
{
do
*cp2-- = '\0';
while (isspace (*cp2));
}
value = val.dptr;
/* mwhere gets just the module name */
mwhere = xstrdup (mname);
mfile = cp + 1;
/* put the / back in mname */
*cp = '/';
goto found;
}
/* put the / back in mname */
*cp = '/';
}
/* if we got here, we couldn't find it using our search, so give up */
error (0, 0, "cannot find module `%s' - ignored", mname);
err++;
if (mwhere)
free (mwhere);
return (err);
/*
* At this point, we found what we were looking for in one
* of the many different forms.
*/
found:
/* copy value to our own string since if we go recursive we'll be
really screwed if we do another dbm lookup */
zvalue = xstrdup (value);
value = zvalue;
/* search the value for the special delimiter and save for later */
if ((cp = index (value, CVSMODULE_SPEC)) != NULL)
{
*cp = '\0'; /* null out the special char */
spec_opt = cp + 1; /* save the options for later */
if (cp != value) /* strip whitespace if necessary */
while (isspace (*--cp))
*cp = '\0';
if (cp == value)
{
/*
* we had nothing but special options, so skip arg
* parsing and regular stuff entirely
*
* If there were only special ones though, we must
* make the appropriate directory and cd to it
*/
char *dir;
/* XXX - XXX - MAJOR HACK - DO NOT SHIP - this needs to
be !pipeout, but we don't know that here yet */
if (!run_module_prog)
goto out;
dir = where ? where : mname;
/* XXX - think about making null repositories at each dir here
instead of just at the bottom */
make_directories (dir);
if (chdir (dir) < 0)
{
error (0, errno, "cannot chdir to %s", dir);
spec_opt = NULL;
err++;
goto out;
}
if (!isfile (CVSADM) && !isfile (OCVSADM))
{
char nullrepos[PATH_MAX];
(void) sprintf (nullrepos, "%s/%s/%s", CVSroot,
CVSROOTADM, CVSNULLREPOS);
if (!isfile (nullrepos))
(void) mkdir (nullrepos, 0777);
Create_Admin (".", nullrepos, (char *) NULL, (char *) NULL);
if (!noexec)
{
FILE *fp;
fp = open_file (CVSADM_ENTSTAT, "w+");
if (fclose (fp) == EOF)
error (1, errno, "cannot close %s", CVSADM_ENTSTAT);
}
}
out:
goto do_special;
}
}
/* don't do special options only part of a module was specified */
if (mfile != NULL)
spec_opt = NULL;
/*
* value now contains one of the following:
* 1) dir
* 2) dir file
* 3) the value from modules without any special args
* [ args ] dir [file] [file] ...
* or -a module [ module ] ...
*/
/* Put the value on a line with XXX prepended for getopt to eat */
(void) sprintf (line, "%s %s", "XXX", value);
/* turn the line into an argv[] array */
line2argv (&modargc, xmodargv, line);
modargv = xmodargv;
/* parse the args */
optind = 1;
while ((c = gnu_getopt (modargc, modargv, CVSMODULE_OPTS)) != -1)
{
switch (c)
{
case 'a':
alias = 1;
break;
case 'd':
if (mwhere)
free (mwhere);
mwhere = xstrdup (optarg);
break;
case 'i':
checkin_prog = optarg;
break;
case 'l':
local_specified = 1;
case 'o':
checkout_prog = optarg;
break;
case 't':
tag_prog = optarg;
break;
case 'u':
update_prog = optarg;
break;
case '?':
error (0, 0,
"modules file has invalid option for key %s value %s",
key.dptr, val.dptr);
err++;
if (mwhere)
free (mwhere);
free (zvalue);
return (err);
}
}
modargc -= optind;
modargv += optind;
if (modargc == 0)
{
error (0, 0, "modules file missing directory for module %s", mname);
if (mwhere)
free (mwhere);
free (zvalue);
return (++err);
}
/* if this was an alias, call ourselves recursively for each module */
if (alias)
{
int i;
for (i = 0; i < modargc; i++)
err += do_module (db, modargv[i], m_type, msg, callback_proc,
where, shorten, local_specified,
run_module_prog, extra_arg);
if (mwhere)
free (mwhere);
free (zvalue);
return (err);
}
/* otherwise, process this module */
err += callback_proc (&modargc, modargv, where, mwhere, mfile, shorten,
local_specified, mname, msg);
/* clean up */
free_names (&modargc, modargv);
/* if there were special include args, process them now */
do_special:
/* blow off special options if -l was specified */
if (local_specified)
spec_opt = NULL;
while (spec_opt != NULL)
{
char *next_opt;
cp = index (spec_opt, CVSMODULE_SPEC);
if (cp != NULL)
{
/* save the beginning of the next arg */
next_opt = cp + 1;
/* strip whitespace off the end */
do
*cp = '\0';
while (isspace (*--cp));
}
else
next_opt = NULL;
/* strip whitespace from front */
while (isspace (*spec_opt))
spec_opt++;
if (*spec_opt == '\0')
error (0, 0, "Mal-formed %c option for module %s - ignored",
CVSMODULE_SPEC, mname);
else
err += do_module (db, spec_opt, m_type, msg, callback_proc,
(char *) NULL, 0, local_specified,
run_module_prog, extra_arg);
spec_opt = next_opt;
}
/* write out the checkin/update prog files if necessary */
if (err == 0 && !noexec && m_type == CHECKOUT && run_module_prog)
{
FILE *fp;
if (checkin_prog != NULL)
{
fp = open_file (CVSADM_CIPROG, "w+");
(void) fprintf (fp, "%s\n", checkin_prog);
if (fclose (fp) == EOF)
error (1, errno, "cannot close %s", CVSADM_CIPROG);
}
if (update_prog != NULL)
{
fp = open_file (CVSADM_UPROG, "w+");
(void) fprintf (fp, "%s\n", update_prog);
if (fclose (fp) == EOF)
error (1, errno, "cannot close %s", CVSADM_UPROG);
}
}
/* cd back to where we started */
if (chdir (cwd) < 0)
error (1, errno, "failed chdir to %s!", cwd);
/* run checkout or tag prog if appropriate */
if (err == 0 && run_module_prog)
{
if ((m_type == TAG && tag_prog != NULL) ||
(m_type == CHECKOUT && checkout_prog != NULL))
{
/*
* If a relative pathname is specified as the checkout or
* tag proc, try to tack on the current "where" value.
* if we can't find a matching program, just punt and use
* whatever is specified in the modules file.
*/
char real_prog[PATH_MAX];
char *prog = (m_type == TAG ? tag_prog : checkout_prog);
char *real_where = (where != NULL ? where : mwhere);
if ((*prog != '/') && (*prog != '.'))
{
(void) sprintf (real_prog, "%s/%s", real_where, prog);
if (isfile (real_prog))
prog = real_prog;
}
run_setup ("%s %s", prog, real_where);
if (extra_arg)
run_arg (extra_arg);
if (!quiet)
{
(void) printf ("%s %s: Executing '", program_name,
command_name);
run_print (stdout);
(void) printf ("'\n");
}
err += run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
}
}
/* clean up */
if (mwhere)
free (mwhere);
free (zvalue);
return (err);
}
/* - Read all the records from the modules database into an array.
- Sort the array depending on what format is desired.
- Print the array in the format desired.
Currently, there are only two "desires":
1. Sort by module name and format the whole entry including switches,
files and the comment field: (Including aliases)
modulename -s switches, one per line, even if
-i it has many switches.
Directories and files involved, formatted
to cover multiple lines if necessary.
# Comment, also formatted to cover multiple
# lines if necessary.
2. Sort by status field string and print: (*not* including aliases)
modulename STATUS Directories and files involved, formatted
to cover multiple lines if necessary.
# Comment, also formatted to cover multiple
# lines if necessary.
*/
static struct sortrec *s_head;
static int s_max = 0; /* Number of elements allocated */
static int s_count = 0; /* Number of elements used */
static int Status;
static char def_status[] = "NONE";
/* Sort routine for qsort:
- If we want the "Status" field to be sorted, check it first.
- Then compare the "module name" fields. Since they are unique, we don't
have to look further.
*/
static int
sort_order (l, r)
CONST PTR l;
CONST PTR r;
{
int i;
CONST struct sortrec *left = (CONST struct sortrec *) l;
CONST struct sortrec *right = (CONST struct sortrec *) r;
if (Status)
{
/* If Sort by status field, compare them. */
if ((i = strcmp (left->status, right->status)) != 0)
return (i);
}
return (strcmp (left->modname, right->modname));
}
static void
save_d (k, ks, d, ds)
char *k;
int ks;
char *d;
int ds;
{
char *cp, *cp2;
struct sortrec *s_rec;
if (Status && *d == '-' && *(d + 1) == 'a')
return; /* We want "cvs co -s" and it is an alias! */
if (s_count == s_max)
{
s_max += 64;
s_head = (struct sortrec *) xrealloc ((char *) s_head, s_max * sizeof (*s_head));
}
s_rec = &s_head[s_count];
s_rec->modname = cp = xmalloc (ks + 1);
(void) strncpy (cp, k, ks);
*(cp + ks) = '\0';
s_rec->rest = cp2 = xmalloc (ds + 1);
cp = d;
*(cp + ds) = '\0'; /* Assumes an extra byte at end of static dbm buffer */
while (isspace (*cp))
cp++;
/* Turn <spaces> into one ' ' -- makes the rest of this routine simpler */
while (*cp)
{
if (isspace (*cp))
{
*cp2++ = ' ';
while (isspace (*cp))
cp++;
}
else
*cp2++ = *cp++;
}
*cp2 = '\0';
/* Look for the "-s statusvalue" text */
if (Status)
{
s_rec->status = def_status;
/* Minor kluge, but general enough to maintain */
for (cp = s_rec->rest; (cp2 = index (cp, '-')) != NULL; cp = ++cp2)
{
if (*(cp2 + 1) == 's' && *(cp2 + 2) == ' ')
{
s_rec->status = (cp2 += 3);
while (*cp2 != ' ')
cp2++;
*cp2++ = '\0';
cp = cp2;
break;
}
}
}
else
cp = s_rec->rest;
/* Find comment field, clean up on all three sides & compress blanks */
if ((cp2 = cp = index (cp, '#')) != NULL)
{
if (*--cp2 == ' ')
*cp2 = '\0';
if (*++cp == ' ')
cp++;
s_rec->comment = cp;
}
else
s_rec->comment = "";
s_count++;
}
void
cat_module (status)
int status;
{
DBM *db;
datum key, val;
int i, c, wid, argc, cols = 80, indent, fill;
int moduleargc;
struct sortrec *s_h;
char *cp, *cp2, **argv;
char line[MAXLINELEN], *moduleargv[MAXFILEPERDIR];
#ifdef sun
#ifdef TIOCGSIZE
struct ttysize ts;
(void) ioctl (0, TIOCGSIZE, &ts);
cols = ts.ts_cols;
#endif
#else
#ifdef TIOCGWINSZ
struct winsize ws;
(void) ioctl (0, TIOCGWINSZ, &ws);
cols = ws.ws_col;
#endif
#endif
Status = status;
/* Read the whole modules file into allocated records */
if (!(db = open_module ()))
error (1, 0, "failed to open the modules file");
for (key = dbm_firstkey (db); key.dptr != NULL; key = dbm_nextkey (db))
{
val = dbm_fetch (db, key);
if (val.dptr != NULL)
save_d (key.dptr, key.dsize, val.dptr, val.dsize);
}
/* Sort the list as requested */
qsort ((PTR) s_head, s_count, sizeof (struct sortrec), sort_order);
/*
* Run through the sorted array and format the entries
* indent = space for modulename + space for status field
*/
indent = 12 + (status * 12);
fill = cols - (indent + 2);
for (s_h = s_head, i = 0; i < s_count; i++, s_h++)
{
/* Print module name (and status, if wanted) */
(void) printf ("%-12s", s_h->modname);
if (status)
{
(void) printf (" %-11s", s_h->status);
if (s_h->status != def_status)
*(s_h->status + strlen (s_h->status)) = ' ';
}
/* Parse module file entry as command line and print options */
(void) sprintf (line, "%s %s", s_h->modname, s_h->rest);
line2argv (&moduleargc, moduleargv, line);
argc = moduleargc;
argv = moduleargv;
optind = 1;
wid = 0;
while ((c = gnu_getopt (argc, argv, CVSMODULE_OPTS)) != -1)
{
if (!status)
{
if (c == 'a')
{
(void) printf (" -a");
wid += 3; /* Could just set it to 3 */
}
else
{
if (strlen (optarg) + 4 + wid > (unsigned) fill)
{
(void) printf ("\n%*s", indent, "");
wid = 0;
}
(void) printf (" -%c %s", c, optarg);
wid += strlen (optarg) + 4;
}
}
}
argc -= optind;
argv += optind;
/* Format and Print all the files and directories */
for (; argc--; argv++)
{
if (strlen (*argv) + wid > (unsigned) fill)
{
(void) printf ("\n%*s", indent, "");
wid = 0;
}
(void) printf (" %s", *argv);
wid += strlen (*argv) + 1;
}
(void) printf ("\n");
/* Format the comment field -- save_d (), compressed spaces */
for (cp2 = cp = s_h->comment; *cp; cp2 = cp)
{
(void) printf ("%*s # ", indent, "");
if (strlen (cp2) < (unsigned) (fill - 2))
{
(void) printf ("%s\n", cp2);
break;
}
cp += fill - 2;
while (*cp != ' ' && cp > cp2)
cp--;
if (cp == cp2)
{
(void) printf ("%s\n", cp2);
break;
}
*cp++ = '\0';
(void) printf ("%s\n", cp2);
}
}
}

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* No Difference
*
* The user file looks modified judging from its time stamp; however it needn't
* be. No_difference() finds out whether it is or not. If it is not, it
* updates the administration.
*
* returns 0 if no differences are found and non-zero otherwise
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)no_diff.c 1.35 92/03/31";
#endif
int
No_Difference (file, vers, entries)
char *file;
Vers_TS *vers;
List *entries;
{
Node *p;
char tmp[L_tmpnam+1];
int ret;
char *ts, *options;
int retcode = 0;
if (!vers->srcfile || !vers->srcfile->path)
return (-1); /* different since we couldn't tell */
if (vers->entdata && vers->entdata->options)
options = xstrdup (vers->entdata->options);
else
options = xstrdup ("");
run_setup ("%s%s -p -q -r%s %s", Rcsbin, RCS_CO,
vers->vn_user ? vers->vn_user : "", options);
run_arg (vers->srcfile->path);
if ((retcode = run_exec (RUN_TTY, tmpnam (tmp), RUN_TTY, RUN_REALLY)) == 0)
{
if (!iswritable (file)) /* fix the modes as a side effect */
xchmod (file, 1);
/* do the byte by byte compare */
if (xcmp (file, tmp) == 0)
{
if (cvswrite == FALSE) /* fix the modes as a side effect */
xchmod (file, 0);
/* no difference was found, so fix the entries file */
ts = time_stamp (file);
Register (entries, file,
vers->vn_user ? vers->vn_user : vers->vn_rcs, ts,
options, vers->tag, vers->date);
free (ts);
/* update the entdata pointer in the vers_ts structure */
p = findnode (entries, file);
vers->entdata = (Entnode *) p->data;
ret = 0;
}
else
ret = 1; /* files were really different */
}
else
{
error (0, retcode == -1 ? errno : 0,
"could not check out revision %s of %s", vers->vn_user, file);
ret = -1; /* different since we couldn't tell */
}
if (trace)
(void) fprintf (stderr, "-> unlink(%s)\n", tmp);
(void) unlink (tmp);
free (options);
return (ret);
}

View File

@ -0,0 +1,147 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)parseinfo.c 1.16 92/04/10";
#endif
/*
* Parse the INFOFILE file for the specified REPOSITORY. Invoke CALLPROC for
* each line in the file that matches the REPOSITORY.
* Return 0 for success, -1 if there was not an INFOFILE, and >0 for failure.
*/
int
Parse_Info (infofile, repository, callproc, all)
char *infofile;
char *repository;
int (*callproc) ();
int all;
{
int err = 0;
FILE *fp_info;
char infopath[PATH_MAX];
char line[MAXLINELEN];
char *default_value = NULL;
int callback_done, line_number;
char *cp, *exp, *value, *srepos;
CONST char *regex_err;
if (CVSroot == NULL)
{
/* XXX - should be error maybe? */
error (0, 0, "CVSROOT variable not set");
return (1);
}
/* find the info file and open it */
(void) sprintf (infopath, "%s/%s/%s", CVSroot,
CVSROOTADM, infofile);
if ((fp_info = fopen (infopath, "r")) == NULL)
return (0); /* no file -> nothing special done */
/* strip off the CVSROOT if repository was absolute */
srepos = Short_Repository (repository);
/* search the info file for lines that match */
callback_done = line_number = 0;
while (fgets (line, sizeof (line), fp_info) != NULL)
{
line_number++;
/* skip lines starting with # */
if (line[0] == '#')
continue;
/* skip whitespace at beginning of line */
for (cp = line; *cp && isspace (*cp); cp++)
;
/* if *cp is null, the whole line was blank */
if (*cp == '\0')
continue;
/* the regular expression is everything up to the first space */
for (exp = cp; *cp && !isspace (*cp); cp++)
;
if (*cp != '\0')
*cp++ = '\0';
/* skip whitespace up to the start of the matching value */
while (*cp && isspace (*cp))
cp++;
/* no value to match with the regular expression is an error */
if (*cp == '\0')
{
error (0, 0, "syntax error at line %d file %s; ignored",
line_number, infofile);
continue;
}
value = cp;
/* strip the newline off the end of the value */
if ((cp = rindex (value, '\n')) != NULL)
*cp = '\0';
/*
* At this point, exp points to the regular expression, and value
* points to the value to call the callback routine with. Evaluate
* the regular expression against srepos and callback with the value
* if it matches.
*/
/* save the default value so we have it later if we need it */
if (strcmp (exp, "DEFAULT") == 0)
{
default_value = xstrdup (value);
continue;
}
/*
* For a regular expression of "ALL", do the callback always We may
* execute lots of ALL callbacks in addition to one regular matching
* callback or default
*/
if (strcmp (exp, "ALL") == 0)
{
if (all)
err += callproc (repository, value);
else
error(0, 0, "Keyword `ALL' is ignored at line %d in %s file",
line_number, infofile);
continue;
}
/* see if the repository matched this regular expression */
if ((regex_err = re_comp (exp)) != NULL)
{
error (0, 0, "bad regular expression at line %d file %s: %s",
line_number, infofile, regex_err);
continue;
}
if (re_exec (srepos) == 0)
continue; /* no match */
/* it did, so do the callback and note that we did one */
err += callproc (repository, value);
callback_done = 1;
}
(void) fclose (fp_info);
/* if we fell through and didn't callback at all, do the default */
if (callback_done == 0 && default_value != NULL)
err += callproc (repository, default_value);
/* free up space if necessary */
if (default_value != NULL)
free (default_value);
return (err);
}

523
gnu/usr.bin/cvs/cvs/patch.c Normal file
View File

@ -0,0 +1,523 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* Patch
*
* Create a Larry Wall format "patch" file between a previous release and the
* current head of a module, or between two releases. Can specify the
* release as either a date or a revision number.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)patch.c 1.50 92/04/10";
#endif
#if __STDC__
static SIGTYPE patch_cleanup (void);
static Dtype patch_dirproc (char *dir, char *repos, char *update_dir);
static int patch_fileproc (char *file, char *update_dir, char *repository,
List * entries, List * srcfiles);
static int patch_proc (int *pargc, char *argv[], char *xwhere,
char *mwhere, char *mfile, int shorten,
int local_specified, char *mname, char *msg);
#else
static int patch_proc ();
static int patch_fileproc ();
static Dtype patch_dirproc ();
static SIGTYPE patch_cleanup ();
#endif /* __STDC__ */
static int force_tag_match = 1;
static int patch_short = 0;
static int toptwo_diffs = 0;
static int local = 0;
static char *options = NULL;
static char *rev1 = NULL;
static char *rev2 = NULL;
static char *date1 = NULL;
static char *date2 = NULL;
static char tmpfile1[L_tmpnam+1], tmpfile2[L_tmpnam+1], tmpfile3[L_tmpnam+1];
static int unidiff = 0;
static char *patch_usage[] =
{
"Usage: %s %s [-Qflq] [-c|-u] [-s|-t] [-V %%d]\n",
" -r rev|-D date [-r rev2 | -D date2] modules...\n",
"\t-Q\tReally quiet.\n",
"\t-f\tForce a head revision match if tag/date not found.\n",
"\t-l\tLocal directory only, not recursive\n",
"\t-c\tContext diffs (default)\n",
"\t-u\tUnidiff format.\n",
"\t-s\tShort patch - one liner per file.\n",
"\t-t\tTop two diffs - last change made to the file.\n",
"\t-D date\tDate.\n",
"\t-r rev\tRevision - symbolic or numeric.\n",
"\t-V vers\tUse RCS Version \"vers\" for keyword expansion.\n",
NULL
};
int
patch (argc, argv)
int argc;
char *argv[];
{
register int i;
int c;
int err = 0;
DBM *db;
if (argc == -1)
usage (patch_usage);
optind = 1;
while ((c = gnu_getopt (argc, argv, "V:k:cuftsQqlRD:r:")) != -1)
{
switch (c)
{
case 'Q':
really_quiet = 1;
/* FALL THROUGH */
case 'q':
quiet = 1;
break;
case 'f':
force_tag_match = 0;
break;
case 'l':
local = 1;
break;
case 'R':
local = 0;
break;
case 't':
toptwo_diffs = 1;
break;
case 's':
patch_short = 1;
break;
case 'D':
if (rev2 != NULL || date2 != NULL)
error (1, 0,
"no more than two revisions/dates can be specified");
if (rev1 != NULL || date1 != NULL)
date2 = Make_Date (optarg);
else
date1 = Make_Date (optarg);
break;
case 'r':
if (rev2 != NULL || date2 != NULL)
error (1, 0,
"no more than two revisions/dates can be specified");
if (rev1 != NULL || date1 != NULL)
rev2 = optarg;
else
rev1 = optarg;
break;
case 'k':
if (options)
free (options);
options = RCS_check_kflag (optarg);
break;
case 'V':
if (atoi (optarg) <= 0)
error (1, 0, "must specify a version number to -V");
if (options)
free (options);
options = xmalloc (strlen (optarg) + 1 + 2); /* for the -V */
(void) sprintf (options, "-V%s", optarg);
break;
case 'u':
unidiff = 1; /* Unidiff */
break;
case 'c': /* Context diff */
unidiff = 0;
break;
case '?':
default:
usage (patch_usage);
break;
}
}
argc -= optind;
argv += optind;
/* Sanity checks */
if (argc < 1)
usage (patch_usage);
if (toptwo_diffs && patch_short)
error (1, 0, "-t and -s options are mutually exclusive");
if (toptwo_diffs && (date1 != NULL || date2 != NULL ||
rev1 != NULL || rev2 != NULL))
error (1, 0, "must not specify revisions/dates with -t option!");
if (!toptwo_diffs && (date1 == NULL && date2 == NULL &&
rev1 == NULL && rev2 == NULL))
error (1, 0, "must specify at least one revision/date!");
if (date1 != NULL && date2 != NULL)
if (RCS_datecmp (date1, date2) >= 0)
error (1, 0, "second date must come after first date!");
/* if options is NULL, make it a NULL string */
if (options == NULL)
options = xstrdup ("");
/* clean up if we get a signal */
(void) SIG_register (SIGHUP, patch_cleanup);
(void) SIG_register (SIGINT, patch_cleanup);
(void) SIG_register (SIGQUIT, patch_cleanup);
(void) SIG_register (SIGPIPE, patch_cleanup);
(void) SIG_register (SIGTERM, patch_cleanup);
db = open_module ();
for (i = 0; i < argc; i++)
err += do_module (db, argv[i], PATCH, "Patching", patch_proc,
(char *) NULL, 0, 0, 0, (char *) NULL);
close_module (db);
free (options);
patch_cleanup ();
return (err);
}
/*
* callback proc for doing the real work of patching
*/
/* ARGSUSED */
static char where[PATH_MAX];
static int
patch_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified,
mname, msg)
int *pargc;
char *argv[];
char *xwhere;
char *mwhere;
char *mfile;
int shorten;
int local_specified;
char *mname;
char *msg;
{
int err = 0;
int which;
char repository[PATH_MAX];
(void) sprintf (repository, "%s/%s", CVSroot, argv[0]);
(void) strcpy (where, argv[0]);
/* if mfile isn't null, we need to set up to do only part of the module */
if (mfile != NULL)
{
char *cp;
char path[PATH_MAX];
/* if the portion of the module is a path, put the dir part on repos */
if ((cp = rindex (mfile, '/')) != NULL)
{
*cp = '\0';
(void) strcat (repository, "/");
(void) strcat (repository, mfile);
(void) strcat (where, "/");
(void) strcat (where, mfile);
mfile = cp + 1;
}
/* take care of the rest */
(void) sprintf (path, "%s/%s", repository, mfile);
if (isdir (path))
{
/* directory means repository gets the dir tacked on */
(void) strcpy (repository, path);
(void) strcat (where, "/");
(void) strcat (where, mfile);
}
else
{
int i;
/* a file means muck argv */
for (i = 1; i < *pargc; i++)
free (argv[i]);
argv[1] = xstrdup (mfile);
(*pargc) = 2;
}
}
/* cd to the starting repository */
if (chdir (repository) < 0)
{
error (0, errno, "cannot chdir to %s", repository);
return (1);
}
if (force_tag_match)
which = W_REPOS | W_ATTIC;
else
which = W_REPOS;
/* start the recursion processor */
err = start_recursion (patch_fileproc, (int (*) ()) NULL, patch_dirproc,
(int (*) ()) NULL, *pargc - 1, argv + 1, local,
which, 0, 1, where, 1);
return (err);
}
/*
* Called to examine a particular RCS file, as appropriate with the options
* that were set above.
*/
/* ARGSUSED */
static int
patch_fileproc (file, update_dir, repository, entries, srcfiles)
char *file;
char *update_dir;
char *repository;
List *entries;
List *srcfiles;
{
char *vers_tag, *vers_head;
char rcsspace[PATH_MAX];
char *rcs = rcsspace;
Node *p;
RCSNode *rcsfile;
FILE *fp1, *fp2, *fp3;
int ret = 0;
int isattic = 0;
int retcode = 0;
char file1[PATH_MAX], file2[PATH_MAX], strippath[PATH_MAX];
char line1[MAXLINELEN], line2[MAXLINELEN];
char *cp1, *cp2, *commap;
FILE *fp;
/* find the parsed rcs file */
p = findnode (srcfiles, file);
if (p == NULL)
return (1);
rcsfile = (RCSNode *) p->data;
if ((rcsfile->flags & VALID) && (rcsfile->flags & INATTIC))
isattic = 1;
(void) sprintf (rcs, "%s%s", file, RCSEXT);
/* if vers_head is NULL, may have been removed from the release */
if (isattic && rev2 == NULL && date2 == NULL)
vers_head = NULL;
else
vers_head = RCS_getversion (rcsfile, rev2, date2, force_tag_match);
if (toptwo_diffs)
{
if (vers_head == NULL)
return (1);
if (!date1)
date1 = xmalloc (50); /* plenty big :-) */
*date1 = '\0';
if (RCS_getrevtime (rcsfile, vers_head, date1, 1) == -1)
{
if (!really_quiet)
error (0, 0, "cannot find date in rcs file %s revision %s",
rcs, vers_head);
return (1);
}
}
vers_tag = RCS_getversion (rcsfile, rev1, date1, force_tag_match);
if (vers_tag == NULL && (vers_head == NULL || isattic))
return (0); /* nothing known about specified revs */
if (vers_tag && vers_head && strcmp (vers_head, vers_tag) == 0)
return (0); /* not changed between releases */
if (patch_short)
{
(void) printf ("File ");
if (vers_tag == NULL)
(void) printf ("%s is new; current revision %s\n", rcs, vers_head);
else if (vers_head == NULL)
(void) printf ("%s is removed; not included in release %s\n",
rcs, rev2 ? rev2 : date2);
else
(void) printf ("%s changed from revision %s to %s\n",
rcs, vers_tag, vers_head);
return (0);
}
if ((fp1 = fopen (tmpnam (tmpfile1), "w+")) != NULL)
(void) fclose (fp1);
if ((fp2 = fopen (tmpnam (tmpfile2), "w+")) != NULL)
(void) fclose (fp2);
if ((fp3 = fopen (tmpnam (tmpfile3), "w+")) != NULL)
(void) fclose (fp3);
if (fp1 == NULL || fp2 == NULL || fp3 == NULL)
{
error (0, 0, "cannot create temporary files");
ret = 1;
goto out;
}
if (vers_tag != NULL)
{
run_setup ("%s%s %s -p -q -r%s", Rcsbin, RCS_CO, options, vers_tag);
run_arg (rcsfile->path);
if ((retcode = run_exec (RUN_TTY, tmpfile1, RUN_TTY, RUN_NORMAL)) != 0)
{
if (!really_quiet)
error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
"co of revision %s in %s failed", vers_tag, rcs);
ret = 1;
goto out;
}
}
else if (toptwo_diffs)
{
ret = 1;
goto out;
}
if (vers_head != NULL)
{
run_setup ("%s%s %s -p -q -r%s", Rcsbin, RCS_CO, options, vers_head);
run_arg (rcsfile->path);
if ((retcode = run_exec (RUN_TTY, tmpfile2, RUN_TTY, RUN_NORMAL)) != 0)
{
if (!really_quiet)
error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
"co of revision %s in %s failed", vers_head, rcs);
ret = 1;
goto out;
}
}
run_setup ("%s -%c", DIFF, unidiff ? 'u' : 'c');
run_arg (tmpfile1);
run_arg (tmpfile2);
switch (run_exec (RUN_TTY, tmpfile3, RUN_TTY, RUN_NORMAL))
{
case -1: /* fork/wait failure */
error (1, errno, "fork for diff failed on %s", rcs);
break;
case 0: /* nothing to do */
break;
case 1:
/*
* The two revisions are really different, so read the first two
* lines of the diff output file, and munge them to include more
* reasonable file names that "patch" will understand.
*/
fp = open_file (tmpfile3, "r");
if (fgets (line1, sizeof (line1), fp) == NULL ||
fgets (line2, sizeof (line2), fp) == NULL)
{
error (0, errno, "failed to read diff file header %s for %s",
tmpfile3, rcs);
ret = 1;
(void) fclose (fp);
goto out;
}
if (!unidiff)
{
if (strncmp (line1, "*** ", 4) != 0 ||
strncmp (line2, "--- ", 4) != 0 ||
(cp1 = index (line1, '\t')) == NULL ||
(cp2 = index (line2, '\t')) == NULL)
{
error (0, 0, "invalid diff header for %s", rcs);
ret = 1;
(void) fclose (fp);
goto out;
}
}
else
{
if (strncmp (line1, "--- ", 4) != 0 ||
strncmp (line2, "+++ ", 4) != 0 ||
(cp1 = index (line1, '\t')) == NULL ||
(cp2 = index (line2, '\t')) == NULL)
{
error (0, 0, "invalid unidiff header for %s", rcs);
ret = 1;
(void) fclose (fp);
goto out;
}
}
if (CVSroot != NULL)
(void) sprintf (strippath, "%s/", CVSroot);
else
(void) strcpy (strippath, REPOS_STRIP);
if (strncmp (rcs, strippath, strlen (strippath)) == 0)
rcs += strlen (strippath);
commap = rindex (rcs, ',');
*commap = '\0';
if (vers_tag != NULL)
{
(void) sprintf (file1, "%s%s%s:%s", update_dir,
update_dir[0] ? "/" : "", rcs, vers_tag);
}
else
{
(void) strcpy (file1, DEVNULL);
}
(void) sprintf (file2, "%s%s%s:%s", update_dir,
update_dir[0] ? "/" : "", rcs,
vers_head ? vers_head : "removed");
if (unidiff)
{
(void) printf ("diff -u %s %s\n", file1, file2);
(void) printf ("--- %s%s+++ ", file1, cp1);
}
else
{
(void) printf ("diff -c %s %s\n", file1, file2);
(void) printf ("*** %s%s--- ", file1, cp1);
}
if (update_dir[0] != '\0')
(void) printf ("%s/", update_dir);
(void) printf ("%s%s", rcs, cp2);
while (fgets (line1, sizeof (line1), fp) != NULL)
(void) printf ("%s", line1);
(void) fclose (fp);
break;
default:
error (0, 0, "diff failed for %s", rcs);
}
out:
(void) unlink_file (tmpfile1);
(void) unlink_file (tmpfile2);
(void) unlink_file (tmpfile3);
return (ret);
}
/*
* Print a warm fuzzy message
*/
/* ARGSUSED */
static Dtype
patch_dirproc (dir, repos, update_dir)
char *dir;
char *repos;
char *update_dir;
{
if (!quiet)
error (0, 0, "Diffing %s", update_dir);
return (R_PROCESS);
}
/*
* Clean up temporary files
*/
static SIGTYPE
patch_cleanup ()
{
if (tmpfile1[0] != '\0')
(void) unlink_file (tmpfile1);
if (tmpfile2[0] != '\0')
(void) unlink_file (tmpfile2);
if (tmpfile3[0] != '\0')
(void) unlink_file (tmpfile3);
}

View File

@ -0,0 +1 @@
#define PATCHLEVEL 0

1449
gnu/usr.bin/cvs/cvs/rcs.c Normal file

File diff suppressed because it is too large Load Diff

102
gnu/usr.bin/cvs/cvs/rcs.h Normal file
View File

@ -0,0 +1,102 @@
/* @(#)rcs.h 1.14 92/03/31 */
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* RCS source control definitions needed by rcs.c and friends
*/
#define RCS "rcs"
#define RCS_CI "ci"
#define RCS_CO "co"
#define RCS_RLOG "rlog"
#define RCS_DIFF "rcsdiff"
#define RCS_MERGE "merge"
#define RCS_RCSMERGE "rcsmerge"
#define RCS_MERGE_PAT "^>>>>>>> " /* runs "grep" with this pattern */
#define RCSEXT ",v"
#define RCSHEAD "head"
#define RCSBRANCH "branch"
#define RCSSYMBOLS "symbols"
#define RCSDATE "date"
#define RCSDESC "desc"
#define DATEFORM "%02d.%02d.%02d.%02d.%02d.%02d"
#define SDATEFORM "%d.%d.%d.%d.%d.%d"
/*
* Opaque structure definitions used by RCS specific lookup routines
*/
#define VALID 0x1 /* flags field contains valid data */
#define INATTIC 0x2 /* RCS file is located in the Attic */
struct rcsnode
{
int refcount;
int flags;
char *path;
char *head;
char *branch;
List *symbols;
List *versions;
List *dates;
};
typedef struct rcsnode RCSNode;
struct rcsversnode
{
char *version;
char *date;
char *next;
List *branches;
};
typedef struct rcsversnode RCSVers;
/*
* CVS reserves all even-numbered branches for its own use. "magic" branches
* (see rcs.c) are contained as virtual revision numbers (within symbolic
* tags only) off the RCS_MAGIC_BRANCH, which is 0. CVS also reserves the
* ".1" branch for vendor revisions. So, if you do your own branching, you
* should limit your use to odd branch numbers starting at 3.
*/
#define RCS_MAGIC_BRANCH 0
/*
* exported interfaces
*/
#if __STDC__
List *RCS_parsefiles (List * files, char *xrepos);
RCSNode *RCS_parse (char *file, char *repos);
RCSNode *RCS_parsercsfile (char *rcsfile);
char *RCS_check_kflag (char *arg);
char *RCS_getdate (RCSNode * rcs, char *date, int force_tag_match);
char *RCS_gettag (RCSNode * rcs, char *tag, int force_tag_match);
char *RCS_getversion (RCSNode * rcs, char *tag, char *date,
int force_tag_match);
char *RCS_magicrev (RCSNode *rcs, char *rev);
int RCS_isbranch (char *file, char *rev, List *srcfiles);
char *RCS_whatbranch (char *file, char *tag, List *srcfiles);
char *RCS_head (RCSNode * rcs);
int RCS_datecmp (char *date1, char *date2);
time_t RCS_getrevtime (RCSNode * rcs, char *rev, char *date, int fudge);
void RCS_check_tag (char *tag);
void freercsnode (RCSNode ** rnodep);
#else
List *RCS_parsefiles ();
RCSNode *RCS_parse ();
char *RCS_head ();
char *RCS_getversion ();
char *RCS_magicrev ();
int RCS_isbranch ();
char *RCS_whatbranch ();
char *RCS_gettag ();
char *RCS_getdate ();
char *RCS_check_kflag ();
void RCS_check_tag ();
time_t RCS_getrevtime ();
RCSNode *RCS_parsercsfile ();
int RCS_datecmp ();
void freercsnode ();
#endif /* __STDC__ */

View File

@ -0,0 +1,535 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* General recursion handler
*
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)recurse.c 1.22 92/04/10";
#endif
#if __STDC__
static int do_dir_proc (Node * p);
static int do_file_proc (Node * p);
static void addlist (List ** listp, char *key);
#else
static int do_file_proc ();
static int do_dir_proc ();
static void addlist ();
#endif /* __STDC__ */
/*
* Local static versions eliminates the need for globals
*/
static int (*fileproc) ();
static int (*filesdoneproc) ();
static Dtype (*direntproc) ();
static int (*dirleaveproc) ();
static int which;
static Dtype flags;
static int aflag;
static int readlock;
static int dosrcs;
static char update_dir[PATH_MAX];
static char *repository = NULL;
static List *entries = NULL;
static List *srcfiles = NULL;
static List *filelist = NULL;
static List *dirlist = NULL;
/*
* Called to start a recursive command Command line arguments are processed
* if present, otherwise the local directory is processed.
*/
int
start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc,
argc, argv, local, which, aflag, readlock,
update_preload, dosrcs)
int (*fileproc) ();
int (*filesdoneproc) ();
Dtype (*direntproc) ();
int (*dirleaveproc) ();
int argc;
char *argv[];
int local;
int which;
int aflag;
int readlock;
char *update_preload;
int dosrcs;
{
int i, err = 0;
Dtype flags;
if (update_preload == NULL)
update_dir[0] = '\0';
else
(void) strcpy (update_dir, update_preload);
if (local)
flags = R_SKIP_DIRS;
else
flags = R_PROCESS;
/* clean up from any previous calls to start_recursion */
if (repository)
{
free (repository);
repository = (char *) NULL;
}
if (entries)
dellist (&entries);
if (srcfiles)
dellist (&srcfiles);
if (filelist)
dellist (&filelist);
if (dirlist)
dellist (&dirlist);
if (argc == 0)
{
/*
* There were no arguments, so we'll probably just recurse. The
* exception to the rule is when we are called from a directory
* without any CVS administration files. That has always meant to
* process each of the sub-directories, so we pretend like we were
* called with the list of sub-dirs of the current dir as args
*/
if ((which & W_LOCAL) && !isdir (CVSADM) && !isdir (OCVSADM))
dirlist = Find_Dirs ((char *) NULL, W_LOCAL);
else
addlist (&dirlist, ".");
err += do_recursion (fileproc, filesdoneproc, direntproc,
dirleaveproc, flags, which, aflag,
readlock, dosrcs);
}
else
{
/*
* There were arguments, so we have to handle them by hand. To do
* that, we set up the filelist and dirlist with the arguments and
* call do_recursion. do_recursion recognizes the fact that the
* lists are non-null when it starts and doesn't update them
*/
/* look for args with /-s in them */
for (i = 0; i < argc; i++)
if (index (argv[i], '/') != NULL)
break;
/* if we didn't find any hard one's, do it the easy way */
if (i == argc)
{
/* set up the lists */
for (i = 0; i < argc; i++)
{
if (isdir (argv[i]))
addlist (&dirlist, argv[i]);
else
{
if (isdir (CVSADM) || isdir (OCVSADM))
{
char *repos;
char tmp[PATH_MAX];
repos = Name_Repository ((char *) NULL, update_dir);
(void) sprintf (tmp, "%s/%s", repos, argv[i]);
if (isdir (tmp))
addlist (&dirlist, argv[i]);
else
addlist (&filelist, argv[i]);
free (repos);
}
else
addlist (&filelist, argv[i]);
}
}
/* we aren't recursive if no directories were specified */
if (dirlist == NULL)
local = 1;
/* process the lists */
err += do_recursion (fileproc, filesdoneproc, direntproc,
dirleaveproc, flags, which, aflag,
readlock, dosrcs);
}
/* otherwise - do it the hard way */
else
{
char *cp;
char *dir = (char *) NULL;
char *comp = (char *) NULL;
char *oldupdate = (char *) NULL;
char savewd[PATH_MAX];
if (getwd (savewd) == NULL)
error (1, 0, "could not get working directory: %s", savewd);
for (i = 0; i < argc; i++)
{
/* split the arg into the dir and component parts */
dir = xstrdup (argv[i]);
if ((cp = rindex (dir, '/')) != NULL)
{
*cp = '\0';
comp = xstrdup (cp + 1);
oldupdate = xstrdup (update_dir);
if (update_dir[0] != '\0')
(void) strcat (update_dir, "/");
(void) strcat (update_dir, dir);
}
else
{
comp = xstrdup (dir);
if (dir)
free (dir);
dir = (char *) NULL;
}
/* chdir to the appropriate place if necessary */
if (dir && chdir (dir) < 0)
error (1, errno, "could not chdir to %s", dir);
/* set up the list */
if (isdir (comp))
addlist (&dirlist, comp);
else
{
if (isdir (CVSADM) || isdir (OCVSADM))
{
char *repos;
char tmp[PATH_MAX];
repos = Name_Repository ((char *) NULL, update_dir);
(void) sprintf (tmp, "%s/%s", repos, comp);
if (isdir (tmp))
addlist (&dirlist, comp);
else
addlist (&filelist, comp);
free (repos);
}
else
addlist (&filelist, comp);
}
/* do the recursion */
err += do_recursion (fileproc, filesdoneproc, direntproc,
dirleaveproc, flags, which,
aflag, readlock, dosrcs);
/* chdir back and fix update_dir if necessary */
if (dir && chdir (savewd) < 0)
error (1, errno, "could not chdir to %s", dir);
if (oldupdate)
{
(void) strcpy (update_dir, oldupdate);
free (oldupdate);
}
}
if (dir)
free (dir);
if (comp)
free (comp);
}
}
return (err);
}
/*
* Implement the recursive policies on the local directory. This may be
* called directly, or may be called by start_recursion
*/
int
do_recursion (xfileproc, xfilesdoneproc, xdirentproc, xdirleaveproc,
xflags, xwhich, xaflag, xreadlock, xdosrcs)
int (*xfileproc) ();
int (*xfilesdoneproc) ();
Dtype (*xdirentproc) ();
int (*xdirleaveproc) ();
Dtype xflags;
int xwhich;
int xaflag;
int xreadlock;
int xdosrcs;
{
int err = 0;
int dodoneproc = 1;
char *srepository;
/* do nothing if told */
if (xflags == R_SKIP_ALL)
return (0);
/* set up the static vars */
fileproc = xfileproc;
filesdoneproc = xfilesdoneproc;
direntproc = xdirentproc;
dirleaveproc = xdirleaveproc;
flags = xflags;
which = xwhich;
aflag = xaflag;
readlock = noexec ? 0 : xreadlock;
dosrcs = xdosrcs;
/*
* Fill in repository with the current repository
*/
if (which & W_LOCAL)
{
if (isdir (CVSADM) || isdir (OCVSADM))
repository = Name_Repository ((char *) NULL, update_dir);
else
repository = NULL;
}
else
{
repository = xmalloc (PATH_MAX);
(void) getwd (repository);
}
srepository = repository; /* remember what to free */
/*
* The filesdoneproc needs to be called for each directory where files
* processed, or each directory that is processed by a call where no
* directories were passed in. In fact, the only time we don't want to
* call back the filesdoneproc is when we are processing directories that
* were passed in on the command line (or in the special case of `.' when
* we were called with no args
*/
if (dirlist != NULL && filelist == NULL)
dodoneproc = 0;
/*
* If filelist or dirlist is already set, we don't look again. Otherwise,
* find the files and directories
*/
if (filelist == NULL && dirlist == NULL)
{
/* both lists were NULL, so start from scratch */
if (fileproc != NULL && flags != R_SKIP_FILES)
{
int lwhich = which;
/* be sure to look in the attic if we have sticky tags/date */
if ((lwhich & W_ATTIC) == 0)
if (isreadable (CVSADM_TAG))
lwhich |= W_ATTIC;
/* find the files and fill in entries if appropriate */
filelist = Find_Names (repository, lwhich, aflag, &entries);
}
/* find sub-directories if we will recurse */
if (flags != R_SKIP_DIRS)
dirlist = Find_Dirs (repository, which);
}
else
{
/* something was passed on the command line */
if (filelist != NULL && fileproc != NULL)
{
/* we will process files, so pre-parse entries */
if (which & W_LOCAL)
entries = ParseEntries (aflag);
}
}
/* process the files (if any) */
if (filelist != NULL)
{
/* read lock it if necessary */
if (readlock && repository && Reader_Lock (repository) != 0)
error (1, 0, "read lock failed - giving up");
/* pre-parse the source files */
if (dosrcs && repository)
srcfiles = RCS_parsefiles (filelist, repository);
else
srcfiles = (List *) NULL;
/* process the files */
err += walklist (filelist, do_file_proc);
/* unlock it */
if (readlock)
Lock_Cleanup ();
/* clean up */
dellist (&filelist);
dellist (&srcfiles);
dellist (&entries);
}
/* call-back files done proc (if any) */
if (dodoneproc && filesdoneproc != NULL)
err = filesdoneproc (err, repository, update_dir[0] ? update_dir : ".");
/* process the directories (if necessary) */
if (dirlist != NULL)
err += walklist (dirlist, do_dir_proc);
#ifdef notdef
else if (dirleaveproc != NULL)
err += dirleaveproc(".", err, ".");
#endif
dellist (&dirlist);
/* free the saved copy of the pointer if necessary */
if (srepository)
{
(void) free (srepository);
repository = (char *) NULL;
}
return (err);
}
/*
* Process each of the files in the list with the callback proc
*/
static int
do_file_proc (p)
Node *p;
{
if (fileproc != NULL)
return (fileproc (p->key, update_dir, repository, entries, srcfiles));
else
return (0);
}
/*
* Process each of the directories in the list (recursing as we go)
*/
static int
do_dir_proc (p)
Node *p;
{
char *dir = p->key;
char savewd[PATH_MAX];
char newrepos[PATH_MAX];
List *sdirlist;
char *srepository;
char *cp;
Dtype dir_return = R_PROCESS;
int stripped_dot = 0;
int err = 0;
/* set up update_dir - skip dots if not at start */
if (strcmp (dir, ".") != 0)
{
if (update_dir[0] != '\0')
{
(void) strcat (update_dir, "/");
(void) strcat (update_dir, dir);
}
else
(void) strcpy (update_dir, dir);
/*
* Here we need a plausible repository name for the sub-directory. We
* create one by concatenating the new directory name onto the
* previous repository name. The only case where the name should be
* used is in the case where we are creating a new sub-directory for
* update -d and in that case the generated name will be correct.
*/
if (repository == NULL)
newrepos[0] = '\0';
else
(void) sprintf (newrepos, "%s/%s", repository, dir);
}
else
{
if (update_dir[0] == '\0')
(void) strcpy (update_dir, dir);
if (repository == NULL)
newrepos[0] = '\0';
else
(void) strcpy (newrepos, repository);
}
/* call-back dir entry proc (if any) */
if (direntproc != NULL)
dir_return = direntproc (dir, newrepos, update_dir);
/* only process the dir if the return code was 0 */
if (dir_return != R_SKIP_ALL)
{
/* save our current directory and static vars */
if (getwd (savewd) == NULL)
error (1, 0, "could not get working directory: %s", savewd);
sdirlist = dirlist;
srepository = repository;
dirlist = NULL;
/* cd to the sub-directory */
if (chdir (dir) < 0)
error (1, errno, "could not chdir to %s", dir);
/* honor the global SKIP_DIRS (a.k.a. local) */
if (flags == R_SKIP_DIRS)
dir_return = R_SKIP_DIRS;
/* remember if the `.' will be stripped for subsequent dirs */
if (strcmp (update_dir, ".") == 0)
{
update_dir[0] = '\0';
stripped_dot = 1;
}
/* make the recursive call */
err += do_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc,
dir_return, which, aflag, readlock, dosrcs);
/* put the `.' back if necessary */
if (stripped_dot)
(void) strcpy (update_dir, ".");
/* call-back dir leave proc (if any) */
if (dirleaveproc != NULL)
err = dirleaveproc (dir, err, update_dir);
/* get back to where we started and restore state vars */
if (chdir (savewd) < 0)
error (1, errno, "could not chdir to %s", savewd);
dirlist = sdirlist;
repository = srepository;
}
/* put back update_dir */
if ((cp = rindex (update_dir, '/')) != NULL)
*cp = '\0';
else
update_dir[0] = '\0';
return (err);
}
/*
* Add a node to a list allocating the list if necessary
*/
static void
addlist (listp, key)
List **listp;
char *key;
{
Node *p;
if (*listp == NULL)
*listp = getlist ();
p = getnode ();
p->type = FILES;
p->key = xstrdup (key);
(void) addnode (*listp, p);
}

View File

@ -0,0 +1,219 @@
/*
* Release: "cancel" a checkout in the history log.
*
* - Don't allow release if anything is active - Don't allow release if not
* above or inside repository. - Don't allow release if ./CVS/Repository is
* not the same as the directory specified in the module database.
*
* - Enter a line in the history log indicating the "release". - If asked to,
* delete the local working directory.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)release.c 1.21 92/02/29";
#endif
#if __STDC__
static void release_delete (char *dir);
#else
static void release_delete ();
#endif /* __STDC__ */
static char *release_usage[] =
{
"Usage: %s %s [-d] modules...\n",
"\t-Q\tReally quiet.\n",
"\t-d\tDelete the given directory.\n",
"\t-q\tSomewhat quiet.\n",
NULL
};
static short delete;
int
release (argc, argv)
int argc;
char **argv;
{
FILE *fp;
register int i, c;
register char *cp;
int margc;
DBM *db;
datum key, val;
char *repository, *srepos;
char **margv, *modargv[MAXFILEPERDIR], line[PATH_MAX];
if (argc == -1)
usage (release_usage);
optind = 1;
while ((c = gnu_getopt (argc, argv, "Qdq")) != -1)
{
switch (c)
{
case 'Q':
really_quiet = 1;
/* FALL THROUGH */
case 'q':
quiet = 1;
break;
case 'd':
delete++;
break;
case '?':
default:
usage (release_usage);
break;
}
}
argc -= optind;
argv += optind;
if (!(db = open_module ()))
return (1);
for (i = 0; i < argc; i++)
{
/*
* If we are in a repository, do it. Else if we are in the parent of
* a directory with the same name as the module, "cd" into it and
* look for a repository there.
*/
if (isdir (argv[i]))
{
if (chdir (argv[i]) < 0)
{
if (!really_quiet)
error (0, 0, "can't chdir to: %s", argv[i]);
continue;
}
if (!isdir (CVSADM) && !isdir (OCVSADM))
{
if (!really_quiet)
error (0, 0, "no repository module: %s", argv[i]);
continue;
}
}
else
{
if (!really_quiet)
error (0, 0, "no such directory/module: %s", argv[i]);
continue;
}
repository = Name_Repository ((char *) NULL, (char *) NULL);
srepos = Short_Repository (repository);
/* grab module entry from database and check against short repos */
key.dptr = argv[i];
key.dsize = strlen (key.dptr);
val = dbm_fetch (db, key);
if (!val.dptr)
{
error (0, 0, "no such module name: %s", argv[i]);
continue;
}
val.dptr[val.dsize] = '\0';
if ((cp = index (val.dptr, '#')) != NULL) /* Strip out a comment */
{
do
{
*cp-- = '\0';
} while (isspace (*cp));
}
(void) sprintf (line, "%s %s", key.dptr, val.dptr);
line2argv (&margc, modargv, line);
margv = modargv;
optind = 1;
while (gnu_getopt (margc, margv, CVSMODULE_OPTS) != -1)
/* do nothing */ ;
margc -= optind;
margv += optind;
if (margc < 1)
{
error (0, 0, "modules file missing directory for key %s value %s",
key.dptr, val.dptr);
continue;
}
if (strcmp (*margv, srepos))
{
error (0, 0, "repository mismatch: module[%s], here[%s]",
*margv, srepos);
free (repository);
continue;
}
if (!really_quiet)
{
/*
* Now see if there is any reason not to allow a "Release" This
* is "popen()" instead of "Popen()" since we don't want "-n" to
* stop it.
*/
fp = popen ("cvs -n -q update", "r");
c = 0;
while (fgets (line, sizeof (line), fp))
{
if (index ("MARCZ", *line))
c++;
(void) printf (line);
}
(void) pclose (fp);
(void) printf ("You have [%d] altered files in this repository.\n",
c);
(void) printf ("Are you sure you want to release %smodule `%s': ",
delete ? "(and delete) " : "", argv[i]);
c = !yesno ();
if (c) /* "No" */
{
(void) fprintf (stderr, "** `%s' aborted by user choice.\n",
command_name);
free (repository);
continue;
}
}
/*
* So, we've passed all the tests, go ahead and release it. First,
* log the release, then attempt to delete it.
*/
history_write ('F', argv[i], "", argv[i], ""); /* F == Free */
free (repository);
if (delete)
release_delete (argv[i]);
}
close_module (db);
return (0);
}
/* We want to "rm -r" the repository, but let us be a little paranoid. */
static void
release_delete (dir)
char *dir;
{
struct stat st;
ino_t ino;
int retcode = 0;
(void) stat (".", &st);
ino = st.st_ino;
(void) chdir ("..");
(void) stat (dir, &st);
if (ino != st.st_ino)
{
error (0, 0,
"Parent dir on a different disk, delete of %s aborted", dir);
return;
}
run_setup ("%s -r", RM);
run_arg (dir);
if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
error (0, retcode == -1 ? errno : 0,
"deletion of module %s failed.", dir);
}

View File

@ -0,0 +1,176 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* Remove a File
*
* Removes entries from the present version. The entries will be removed from
* the RCS repository upon the next "commit".
*
* "remove" accepts no options, only file names that are to be removed. The
* file must not exist in the current directory for "remove" to work
* correctly.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)remove.c 1.34 92/04/10";
#endif
#if __STDC__
static int remove_fileproc (char *file, char *update_dir,
char *repository, List *entries,
List *srcfiles);
static Dtype remove_dirproc (char *dir, char *repos, char *update_dir);
#else
static Dtype remove_dirproc ();
static int remove_fileproc ();
#endif
static int local;
static int removed_files;
static int auto_removed_files;
static char *remove_usage[] =
{
"Usage: %s %s [-lR] [files...]\n",
"\t-l\tProcess this directory only (not recursive).\n",
"\t-R\tProcess directories recursively.\n",
NULL
};
int
cvsremove (argc, argv)
int argc;
char *argv[];
{
int c, err;
if (argc == -1)
usage (remove_usage);
optind = 1;
while ((c = gnu_getopt (argc, argv, "lR")) != -1)
{
switch (c)
{
case 'l':
local = 1;
break;
case 'R':
local = 0;
break;
case '?':
default:
usage (remove_usage);
break;
}
}
argc -= optind;
argv += optind;
/* start the recursion processor */
err = start_recursion (remove_fileproc, (int (*) ()) NULL, remove_dirproc,
(int (*) ()) NULL, argc, argv, local,
W_LOCAL, 0, 1, (char *) NULL, 1);
if (removed_files)
error (0, 0, "use '%s commit' to remove %s permanently", program_name,
(removed_files == 1) ? "this file" : "these files");
else
if (!auto_removed_files)
error (0, 0, "no files removed; use `%s' to remove the file first",
RM);
return (err);
}
/*
* remove the file, only if it has already been physically removed
*/
/* ARGSUSED */
static int
remove_fileproc (file, update_dir, repository, entries, srcfiles)
char *file;
char *update_dir;
char *repository;
List *entries;
List *srcfiles;
{
char fname[PATH_MAX];
Vers_TS *vers;
vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL,
file, 0, 0, entries, srcfiles);
if (vers->ts_user != NULL)
{
freevers_ts (&vers);
return (0);
}
if (vers->vn_user == NULL)
{
if (!quiet)
error (0, 0, "nothing known about %s", file);
freevers_ts (&vers);
return (0);
}
if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
{
/*
* It's a file that has been added, but not commited yet. So,
* remove the ,p and ,t file for it and scratch it from the
* entries file.
*/
Scratch_Entry (entries, file);
(void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_OPT);
(void) unlink_file (fname);
(void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_LOG);
(void) unlink_file (fname);
if (!quiet)
error (0, 0, "removed `%s'.", file);
auto_removed_files++;
}
else if (vers->vn_user[0] == '-')
{
freevers_ts (&vers);
return (0);
}
else
{
/* Re-register it with a negative version number. */
(void) strcpy (fname, "-");
(void) strcat (fname, vers->vn_user);
Register (entries, file, fname, vers->ts_rcs, vers->options,
vers->tag, vers->date);
if (!quiet)
{
error (0, 0, "scheduling %s for removal", file);
removed_files++;
}
}
freevers_ts (&vers);
return (0);
}
/*
* Print a warm fuzzy message
*/
/* ARGSUSED */
static Dtype
remove_dirproc (dir, repos, update_dir)
char *dir;
char *repos;
char *update_dir;
{
if (!quiet)
error (0, 0, "Removing %s", update_dir);
return (R_PROCESS);
}

169
gnu/usr.bin/cvs/cvs/repos.c Normal file
View File

@ -0,0 +1,169 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* Name of Repository
*
* Determine the name of the RCS repository and sets "Repository" accordingly.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)repos.c 1.28 92/03/31";
#endif
char *
Name_Repository (dir, update_dir)
char *dir;
char *update_dir;
{
FILE *fpin;
char *ret, *xupdate_dir;
char repos[PATH_MAX];
char path[PATH_MAX];
char tmp[PATH_MAX];
char cvsadm[PATH_MAX];
char ocvsadm[PATH_MAX];
char *cp;
int has_cvsadm = 0, has_ocvsadm = 0;
if (update_dir && *update_dir)
xupdate_dir = update_dir;
else
xupdate_dir = ".";
if (dir != NULL)
{
(void) sprintf (cvsadm, "%s/%s", dir, CVSADM);
(void) sprintf (ocvsadm, "%s/%s", dir, OCVSADM);
}
else
{
(void) strcpy (cvsadm, CVSADM);
(void) strcpy (ocvsadm, OCVSADM);
}
/* sanity checks */
if (!(has_cvsadm = isdir (cvsadm)) && !(has_ocvsadm = isdir (ocvsadm)))
{
error (0, 0, "in directory %s:", xupdate_dir);
error (1, 0, "there is no version here; do '%s checkout' first",
program_name);
}
if (has_ocvsadm)
{
if (has_cvsadm)
{
error (0, 0, "in directory %s:", xupdate_dir);
error (1, 0, "error: both `%s' and `%s' exist; I give up",
CVSADM, OCVSADM);
}
if (rename (ocvsadm, cvsadm) < 0)
{
error (0, 0, "in directory %s:", xupdate_dir);
error (1, errno, "cannot rename `%s' to `%s'; I give up",
OCVSADM, CVSADM);
}
/*
* We have converted the old CVS.adm directory to the new CVS
* directory. Now, convert the Entries file to the new format, if
* necessary.
*/
check_entries (dir);
}
if (dir != NULL)
(void) sprintf (tmp, "%s/%s", dir, CVSADM_ENT);
else
(void) strcpy (tmp, CVSADM_ENT);
if (!isreadable (tmp))
{
error (0, 0, "in directory %s:", xupdate_dir);
error (1, 0, "*PANIC* administration files missing");
}
if (dir != NULL)
(void) sprintf (tmp, "%s/%s", dir, CVSADM_REP);
else
(void) strcpy (tmp, CVSADM_REP);
if (!isreadable (tmp))
{
error (0, 0, "in directory %s:", xupdate_dir);
error (1, 0, "*PANIC* administration files missing");
}
/*
* The assumption here is that the repository is always contained in the
* first line of the "Repository" file.
*/
fpin = open_file (tmp, "r");
if (fgets (repos, PATH_MAX, fpin) == NULL)
{
error (0, 0, "in directory %s:", xupdate_dir);
error (1, errno, "cannot read %s", CVSADM_REP);
}
(void) fclose (fpin);
if ((cp = rindex (repos, '\n')) != NULL)
*cp = '\0'; /* strip the newline */
/*
* If this is a relative repository pathname, turn it into an absolute
* one by tacking on the CVSROOT environment variable. If the CVSROOT
* environment variable is not set, die now.
*/
if (strcmp (repos, "..") == 0 || strncmp (repos, "../", 3) == 0)
{
error (0, 0, "in directory %s:", xupdate_dir);
error (0, 0, "`..'-relative repositories are not supported.");
error (1, 0, "illegal source repository");
}
if (repos[0] != '/')
{
if (CVSroot == NULL)
{
error (0, 0, "in directory %s:", xupdate_dir);
error (0, 0, "must set the CVSROOT environment variable\n");
error (0, 0, "or specify the '-d' option to %s.", program_name);
error (1, 0, "illegal repository setting");
}
(void) strcpy (path, repos);
(void) sprintf (repos, "%s/%s", CVSroot, path);
}
if (!isdir (repos))
{
error (0, 0, "in directory %s:", xupdate_dir);
error (1, 0, "there is no repository %s", repos);
}
/* allocate space to return and fill it in */
strip_path (repos);
ret = xstrdup (repos);
return (ret);
}
/*
* Return a pointer to the repository name relative to CVSROOT from a
* possibly fully qualified repository
*/
char *
Short_Repository (repository)
char *repository;
{
if (repository == NULL)
return (NULL);
/* if repository matches CVSroot at the beginning, strip off CVSroot */
if (strncmp (CVSroot, repository, strlen (CVSroot)) == 0)
return (repository + strlen (CVSroot) + 1);
else
return (repository);
}

403
gnu/usr.bin/cvs/cvs/rtag.c Normal file
View File

@ -0,0 +1,403 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* Rtag
*
* Add or delete a symbolic name to an RCS file, or a collection of RCS files.
* Uses the modules database, if necessary.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)rtag.c 1.57 92/04/10";
#endif
#if __STDC__
static Dtype rtag_dirproc (char *dir, char *repos, char *update_dir);
static int rtag_fileproc (char *file, char *update_dir,
char *repository, List * entries,
List * srcfiles);
static int rtag_proc (int *pargc, char *argv[], char *xwhere,
char *mwhere, char *mfile, int shorten,
int local_specified, char *mname, char *msg);
static int rtag_delete (RCSNode *rcsfile);
#else
static int rtag_proc ();
static int rtag_fileproc ();
static Dtype rtag_dirproc ();
static int rtag_delete ();
#endif /* __STDC__ */
static char *symtag;
static char *numtag;
static int delete; /* adding a tag by default */
static int attic_too; /* remove tag from Attic files */
static int branch_mode; /* make an automagic "branch" tag */
static char *date;
static int local; /* recursive by default */
static int force_tag_match = 1; /* force by default */
static char *rtag_usage[] =
{
"Usage: %s %s [-QaflRnq] [-b] [-d] [-r tag|-D date] tag modules...\n",
"\t-Q\tReally quiet.\n",
"\t-a\tClear tag from removed files that would not otherwise be tagged.\n",
"\t-f\tForce a head revision match if tag/date not found.\n",
"\t-l\tLocal directory only, not recursive\n",
"\t-R\tProcess directories recursively.\n",
"\t-n\tNo execution of 'tag program'\n",
"\t-q\tSomewhat quiet.\n",
"\t-d\tDelete the given Tag.\n",
"\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n",
"\t-[rD]\tExisting tag or Date.\n",
NULL
};
int
rtag (argc, argv)
int argc;
char *argv[];
{
register int i;
int c;
DBM *db;
int run_module_prog = 1;
int err = 0;
if (argc == -1)
usage (rtag_usage);
optind = 1;
while ((c = gnu_getopt (argc, argv, "anfQqlRdbr:D:")) != -1)
{
switch (c)
{
case 'a':
attic_too = 1;
break;
case 'n':
run_module_prog = 0;
break;
case 'Q':
really_quiet = 1;
/* FALL THROUGH */
case 'q':
quiet = 1;
break;
case 'l':
local = 1;
break;
case 'R':
local = 0;
break;
case 'd':
delete = 1;
break;
case 'f':
force_tag_match = 0;
break;
case 'b':
branch_mode = 1;
break;
case 'r':
numtag = optarg;
break;
case 'D':
if (date)
free (date);
date = Make_Date (optarg);
break;
case '?':
default:
usage (rtag_usage);
break;
}
}
argc -= optind;
argv += optind;
if (argc < 2)
usage (rtag_usage);
symtag = argv[0];
argc--;
argv++;
if (date && numtag)
error (1, 0, "-r and -D options are mutually exclusive");
if (delete && branch_mode)
error (0, 0, "warning: -b ignored with -d options");
RCS_check_tag (symtag);
db = open_module ();
for (i = 0; i < argc; i++)
{
/* XXX last arg should be repository, but doesn't make sense here */
history_write ('T', (delete ? "D" : (numtag ? numtag :
(date ? date : "A"))), symtag, argv[i], "");
err += do_module (db, argv[i], TAG, delete ? "Untagging" : "Tagging",
rtag_proc, (char *) NULL, 0, 0, run_module_prog,
symtag);
}
close_module (db);
return (err);
}
/*
* callback proc for doing the real work of tagging
*/
/* ARGSUSED */
static int
rtag_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified,
mname, msg)
int *pargc;
char *argv[];
char *xwhere;
char *mwhere;
char *mfile;
int shorten;
int local_specified;
char *mname;
char *msg;
{
int err = 0;
int which;
char repository[PATH_MAX];
char where[PATH_MAX];
(void) sprintf (repository, "%s/%s", CVSroot, argv[0]);
(void) strcpy (where, argv[0]);
/* if mfile isn't null, we need to set up to do only part of the module */
if (mfile != NULL)
{
char *cp;
char path[PATH_MAX];
/* if the portion of the module is a path, put the dir part on repos */
if ((cp = rindex (mfile, '/')) != NULL)
{
*cp = '\0';
(void) strcat (repository, "/");
(void) strcat (repository, mfile);
(void) strcat (where, "/");
(void) strcat (where, mfile);
mfile = cp + 1;
}
/* take care of the rest */
(void) sprintf (path, "%s/%s", repository, mfile);
if (isdir (path))
{
/* directory means repository gets the dir tacked on */
(void) strcpy (repository, path);
(void) strcat (where, "/");
(void) strcat (where, mfile);
}
else
{
int i;
/* a file means muck argv */
for (i = 1; i < *pargc; i++)
free (argv[i]);
argv[1] = xstrdup (mfile);
(*pargc) = 2;
}
}
/* chdir to the starting directory */
if (chdir (repository) < 0)
{
error (0, errno, "cannot chdir to %s", repository);
return (1);
}
if (delete || attic_too || (force_tag_match && numtag))
which = W_REPOS | W_ATTIC;
else
which = W_REPOS;
/* start the recursion processor */
err = start_recursion (rtag_fileproc, (int (*) ()) NULL, rtag_dirproc,
(int (*) ()) NULL, *pargc - 1, argv + 1, local,
which, 0, 1, where, 1);
return (err);
}
/*
* Called to tag a particular file, as appropriate with the options that were
* set above.
*/
/* ARGSUSED */
static int
rtag_fileproc (file, update_dir, repository, entries, srcfiles)
char *file;
char *update_dir;
char *repository;
List *entries;
List *srcfiles;
{
Node *p;
RCSNode *rcsfile;
char *version, *rev;
int retcode = 0;
/* find the parsed RCS data */
p = findnode (srcfiles, file);
if (p == NULL)
return (1);
rcsfile = (RCSNode *) p->data;
/*
* For tagging an RCS file which is a symbolic link, you'd best be
* running with RCS 5.6, since it knows how to handle symbolic links
* correctly without breaking your link!
*/
if (delete)
return (rtag_delete (rcsfile));
/*
* If we get here, we are adding a tag. But, if -a was specified, we
* need to check to see if a -r or -D option was specified. If neither
* was specified and the file is in the Attic, remove the tag.
*/
if (attic_too && (!numtag && !date))
{
if ((rcsfile->flags & VALID) && (rcsfile->flags & INATTIC))
return (rtag_delete (rcsfile));
}
version = RCS_getversion (rcsfile, numtag, date, force_tag_match);
if (version == NULL)
{
/* If -a specified, clean up any old tags */
if (attic_too)
(void) rtag_delete (rcsfile);
if (!quiet && !force_tag_match)
{
error (0, 0, "cannot find tag `%s' in `%s'",
numtag ? numtag : "head", rcsfile->path);
return (1);
}
return (0);
}
if (numtag && isdigit (*numtag) && strcmp (numtag, version) != 0)
{
/*
* We didn't find a match for the numeric tag that was specified, but
* that's OK. just pass the numeric tag on to rcs, to be tagged as
* specified. Could get here if one tried to tag "1.1.1" and there
* was a 1.1.1 branch with some head revision. In this case, we want
* the tag to reference "1.1.1" and not the revision at the head of
* the branch. Use a symbolic tag for that.
*/
rev = branch_mode ? RCS_magicrev (rcsfile, version) : numtag;
run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, symtag, numtag);
}
else
{
char *oversion;
/*
* As an enhancement for the case where a tag is being re-applied to
* a large body of a module, make one extra call to Version_Number to
* see if the tag is already set in the RCS file. If so, check to
* see if it needs to be moved. If not, do nothing. This will
* likely save a lot of time when simply moving the tag to the
* "current" head revisions of a module -- which I have found to be a
* typical tagging operation.
*/
oversion = RCS_getversion (rcsfile, symtag, (char *) 0, 1);
if (oversion != NULL)
{
if (strcmp (version, oversion) == 0)
{
free (version);
free (oversion);
return (0);
}
free (oversion);
}
rev = branch_mode ? RCS_magicrev (rcsfile, version) : version;
run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, symtag, rev);
}
run_arg (rcsfile->path);
if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
{
if (!quiet)
error (0, retcode == -1 ? errno : 0,
"failed to set tag `%s' to revision `%s' in `%s'",
symtag, rev, rcsfile->path);
free (version);
return (1);
}
free (version);
return (0);
}
/*
* If -d is specified, "force_tag_match" is set, so that this call to
* Version_Number() will return a NULL version string if the symbolic
* tag does not exist in the RCS file.
*
* If the -r flag was used, numtag is set, and we only delete the
* symtag from files that have numtag.
*
* This is done here because it's MUCH faster than just blindly calling
* "rcs" to remove the tag... trust me.
*/
static int
rtag_delete (rcsfile)
RCSNode *rcsfile;
{
char *version;
int retcode;
if (numtag)
{
version = RCS_getversion (rcsfile, numtag, (char *) 0, 1);
if (version == NULL)
return (0);
free (version);
}
version = RCS_getversion (rcsfile, symtag, (char *) 0, 1);
if (version == NULL)
return (0);
free (version);
run_setup ("%s%s -q -N%s", Rcsbin, RCS, symtag);
run_arg (rcsfile->path);
if ((retcode = run_exec (RUN_TTY, RUN_TTY, DEVNULL, RUN_NORMAL)) != 0)
{
if (!quiet)
error (0, retcode == -1 ? errno : 0,
"failed to remove tag `%s' from `%s'", symtag,
rcsfile->path);
return (1);
}
return (0);
}
/*
* Print a warm fuzzy message
*/
/* ARGSUSED */
static Dtype
rtag_dirproc (dir, repos, update_dir)
char *dir;
char *repos;
char *update_dir;
{
if (!quiet)
error (0, 0, "%s %s", delete ? "Untagging" : "Tagging", update_dir);
return (R_PROCESS);
}

View File

@ -0,0 +1,230 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* Status Information
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)status.c 1.48 92/03/31";
#endif
#if __STDC__
static Dtype status_dirproc (char *dir, char *repos, char *update_dir);
static int status_fileproc (char *file, char *update_dir,
char *repository, List * entries,
List * srcfiles);
static int tag_list_proc (Node * p);
#else
static int tag_list_proc ();
static int status_fileproc ();
static Dtype status_dirproc ();
#endif /* __STDC__ */
static int local = 0;
static int long_format = 0;
static char *status_usage[] =
{
"Usage: %s %s [-vlR] [files...]\n",
"\t-v\tVerbose format; includes tag information for the file\n",
"\t-l\tProcess this directory only (not recursive).\n",
"\t-R\tProcess directories recursively.\n",
NULL
};
int
status (argc, argv)
int argc;
char *argv[];
{
int c;
int err = 0;
if (argc == -1)
usage (status_usage);
optind = 1;
while ((c = gnu_getopt (argc, argv, "vlR")) != -1)
{
switch (c)
{
case 'v':
long_format = 1;
break;
case 'l':
local = 1;
break;
case 'R':
local = 0;
break;
case '?':
default:
usage (status_usage);
break;
}
}
argc -= optind;
argv += optind;
/* start the recursion processor */
err = start_recursion (status_fileproc, (int (*) ()) NULL, status_dirproc,
(int (*) ()) NULL, argc, argv, local,
W_LOCAL, 0, 1, (char *) NULL, 1);
return (err);
}
/*
* display the status of a file
*/
/* ARGSUSED */
static int
status_fileproc (file, update_dir, repository, entries, srcfiles)
char *file;
char *update_dir;
char *repository;
List *entries;
List *srcfiles;
{
Ctype status;
char *sstat;
Vers_TS *vers;
status = Classify_File (file, (char *) NULL, (char *) NULL, (char *) NULL,
1, 0, repository, entries, srcfiles, &vers);
switch (status)
{
case T_UNKNOWN:
sstat = "Unknown";
break;
case T_CHECKOUT:
sstat = "Needs Checkout";
break;
case T_CONFLICT:
sstat = "Unresolved Conflict";
break;
case T_ADDED:
sstat = "Locally Added";
break;
case T_REMOVED:
sstat = "Locally Removed";
break;
case T_MODIFIED:
sstat = "Locally Modified";
break;
case T_REMOVE_ENTRY:
sstat = "Entry Invalid";
break;
case T_UPTODATE:
sstat = "Up-to-date";
break;
case T_NEEDS_MERGE:
sstat = "Needs Merge";
break;
default:
sstat = "Classify Error";
break;
}
(void) printf ("===================================================================\n");
if (vers->ts_user == NULL)
(void) printf ("File: no file %s\t\tStatus: %s\n\n", file, sstat);
else
(void) printf ("File: %-17.17s\tStatus: %s\n\n", file, sstat);
if (vers->vn_user == NULL)
(void) printf (" Version:\t\tNo entry for %s\n", file);
else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
(void) printf (" Version:\t\tNew file!\n");
else
(void) printf (" Version:\t\t%s\t%s\n", vers->vn_user,
&vers->ts_rcs[25]);
if (vers->vn_rcs == NULL)
(void) printf (" RCS Version:\tNo revision control file\n");
else
(void) printf (" RCS Version:\t%s\t%s\n", vers->vn_rcs,
vers->srcfile->path);
if (vers->entdata)
{
Entnode *edata;
edata = vers->entdata;
if (edata->tag)
{
if (vers->vn_rcs == NULL)
(void) printf (
" Sticky Tag:\t\t%s - MISSING from RCS file!\n",
edata->tag);
else
{
if (isdigit (edata->tag[0]))
(void) printf (" Sticky Tag:\t\t%s\n", edata->tag);
else
(void) printf (" Sticky Tag:\t\t%s (%s: %s)\n",
edata->tag, numdots (vers->vn_rcs) % 2 ?
"revision" : "branch", vers->vn_rcs);
}
}
else
(void) printf (" Sticky Tag:\t\t(none)\n");
if (edata->date)
(void) printf (" Sticky Date:\t%s\n", edata->date);
else
(void) printf (" Sticky Date:\t(none)\n");
if (edata->options && edata->options[0])
(void) printf (" Sticky Options:\t%s\n", edata->options);
else
(void) printf (" Sticky Options:\t(none)\n");
if (long_format && vers->srcfile)
{
(void) printf ("\n Existing Tags:\n");
if (vers->srcfile->symbols)
(void) walklist (vers->srcfile->symbols, tag_list_proc);
else
(void) printf ("\tNo Tags Exist\n");
}
}
(void) printf ("\n");
freevers_ts (&vers);
return (0);
}
/*
* Print a warm fuzzy message
*/
/* ARGSUSED */
static Dtype
status_dirproc (dir, repos, update_dir)
char *dir;
char *repos;
char *update_dir;
{
if (!quiet)
error (0, 0, "Examining %s", update_dir);
return (R_PROCESS);
}
/*
* Print out a tag and its type
*/
static int
tag_list_proc (p)
Node *p;
{
(void) printf ("\t%-25.25s\t(%s: %s)\n", p->key,
numdots (p->data) % 2 ? "revision" : "branch",
p->data);
return (0);
}

263
gnu/usr.bin/cvs/cvs/tag.c Normal file
View File

@ -0,0 +1,263 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* Tag
*
* Add or delete a symbolic name to an RCS file, or a collection of RCS files.
* Uses the checked out revision in the current directory.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)tag.c 1.56 92/03/31";
#endif
#if __STDC__
static Dtype tag_dirproc (char *dir, char *repos, char *update_dir);
static int tag_fileproc (char *file, char *update_dir,
char *repository, List * entries,
List * srcfiles);
#else
static int tag_fileproc ();
static Dtype tag_dirproc ();
#endif /* __STDC__ */
static char *symtag;
static int delete; /* adding a tag by default */
static int branch_mode; /* make an automagic "branch" tag */
static int local; /* recursive by default */
static char *tag_usage[] =
{
"Usage: %s %s [-QlRq] [-b] [-d] tag [files...]\n",
"\t-Q\tReally quiet.\n",
"\t-l\tLocal directory only, not recursive.\n",
"\t-R\tProcess directories recursively.\n",
"\t-q\tSomewhat quiet.\n",
"\t-d\tDelete the given Tag.\n",
"\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n",
NULL
};
int
tag (argc, argv)
int argc;
char *argv[];
{
int c;
int err = 0;
if (argc == -1)
usage (tag_usage);
optind = 1;
while ((c = gnu_getopt (argc, argv, "QqlRdb")) != -1)
{
switch (c)
{
case 'Q':
really_quiet = 1;
/* FALL THROUGH */
case 'q':
quiet = 1;
break;
case 'l':
local = 1;
break;
case 'R':
local = 0;
break;
case 'd':
delete = 1;
break;
case 'b':
branch_mode = 1;
break;
case '?':
default:
usage (tag_usage);
break;
}
}
argc -= optind;
argv += optind;
if (argc == 0)
usage (tag_usage);
symtag = argv[0];
argc--;
argv++;
if (delete && branch_mode)
error (0, 0, "warning: -b ignored with -d options");
RCS_check_tag (symtag);
/* start the recursion processor */
err = start_recursion (tag_fileproc, (int (*) ()) NULL, tag_dirproc,
(int (*) ()) NULL, argc, argv, local,
W_LOCAL, 0, 1, (char *) NULL, 1);
return (err);
}
/*
* Called to tag a particular file (the currently checked out version is
* tagged with the specified tag - or the specified tag is deleted).
*/
/* ARGSUSED */
static int
tag_fileproc (file, update_dir, repository, entries, srcfiles)
char *file;
char *update_dir;
char *repository;
List *entries;
List *srcfiles;
{
char *version, *oversion;
char *rev;
Vers_TS *vers;
int retcode = 0;
vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL,
file, 0, 0, entries, srcfiles);
if (delete)
{
/*
* If -d is specified, "force_tag_match" is set, so that this call to
* Version_Number() will return a NULL version string if the symbolic
* tag does not exist in the RCS file.
*
* This is done here because it's MUCH faster than just blindly calling
* "rcs" to remove the tag... trust me.
*/
version = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1);
if (version == NULL || vers->srcfile == NULL)
{
freevers_ts (&vers);
return (0);
}
free (version);
run_setup ("%s%s -q -N%s", Rcsbin, RCS, symtag);
run_arg (vers->srcfile->path);
if ((retcode = run_exec (RUN_TTY, RUN_TTY, DEVNULL, RUN_NORMAL)) != 0)
{
if (!quiet)
error (0, retcode == -1 ? errno : 0,
"failed to remove tag %s from %s", symtag,
vers->srcfile->path);
freevers_ts (&vers);
return (1);
}
/* warm fuzzies */
if (!really_quiet)
{
if (update_dir[0])
(void) printf ("D %s/%s\n", update_dir, file);
else
(void) printf ("D %s\n", file);
}
freevers_ts (&vers);
return (0);
}
/*
* If we are adding a tag, we need to know which version we have checked
* out and we'll tag that version.
*/
version = vers->vn_user;
if (version == NULL)
{
freevers_ts (&vers);
return (0);
}
else if (strcmp (version, "0") == 0)
{
if (!quiet)
error (0, 0, "couldn't tag added but un-commited file `%s'", file);
freevers_ts (&vers);
return (0);
}
else if (version[0] == '-')
{
if (!quiet)
error (0, 0, "skipping removed but un-commited file `%s'", file);
freevers_ts (&vers);
return (0);
}
else if (vers->srcfile == NULL)
{
if (!quiet)
error (0, 0, "cannot find revision control file for `%s'", file);
freevers_ts (&vers);
return (0);
}
/*
* As an enhancement for the case where a tag is being re-applied to a
* large number of files, make one extra call to Version_Number to see if
* the tag is already set in the RCS file. If so, check to see if it
* needs to be moved. If not, do nothing. This will likely save a lot of
* time when simply moving the tag to the "current" head revisions of a
* module -- which I have found to be a typical tagging operation.
*/
oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1);
if (oversion != NULL)
{
if (strcmp (version, oversion) == 0)
{
free (oversion);
freevers_ts (&vers);
return (0);
}
free (oversion);
}
rev = branch_mode ? RCS_magicrev (vers->srcfile, version) : version;
run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, symtag, rev);
run_arg (vers->srcfile->path);
if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
{
if (!quiet)
error (0, retcode == -1 ? errno : 0,
"failed to set tag %s to revision %s in %s",
symtag, rev, vers->srcfile->path);
freevers_ts (&vers);
return (1);
}
/* more warm fuzzies */
if (!really_quiet)
{
if (update_dir[0])
(void) printf ("T %s/%s\n", update_dir, file);
else
(void) printf ("T %s\n", file);
}
freevers_ts (&vers);
return (0);
}
/*
* Print a warm fuzzy message
*/
/* ARGSUSED */
static Dtype
tag_dirproc (dir, repos, update_dir)
char *dir;
char *repos;
char *update_dir;
{
if (!quiet)
error (0, 0, "%s %s", delete ? "Untagging" : "Tagging", update_dir);
return (R_PROCESS);
}

1028
gnu/usr.bin/cvs/cvs/update.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,224 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)vers_ts.c 1.36 92/03/31";
#endif
extern char *ctime (); /* XXX - should use gmtime/asctime */
/*
* Fill in and return a Vers_TS structure "user" is the name of the local
* file; entries is the entries file - preparsed for our pleasure. xfiles is
* all source code control files, preparsed for our pleasure
*/
Vers_TS *
Version_TS (repository, options, tag, date, user, force_tag_match,
set_time, entries, xfiles)
char *repository;
char *options;
char *tag;
char *date;
char *user;
int force_tag_match;
int set_time;
List *entries;
List *xfiles;
{
Node *p;
RCSNode *rcsdata;
Vers_TS *vers_ts;
struct stickydirtag *sdtp;
/* get a new Vers_TS struct */
vers_ts = (Vers_TS *) xmalloc (sizeof (Vers_TS));
bzero ((char *) vers_ts, sizeof (*vers_ts));
/*
* look up the entries file entry and fill in the version and timestamp
* if entries is NULL, there is no entries file so don't bother trying to
* look it up (used by checkout -P)
*/
if (entries == NULL)
{
sdtp = NULL;
p = NULL;
}
else
{
p = findnode (entries, user);
sdtp = (struct stickydirtag *) entries->list->data; /* list-private */
}
if (p != NULL)
{
Entnode *entdata = (Entnode *) p->data;
vers_ts->vn_user = xstrdup (entdata->version);
vers_ts->ts_rcs = xstrdup (entdata->timestamp);
if (!tag)
{
if (!(sdtp && sdtp->aflag))
vers_ts->tag = xstrdup (entdata->tag);
}
if (!date)
{
if (!(sdtp && sdtp->aflag))
vers_ts->date = xstrdup (entdata->date);
}
if (!options || (options && *options == '\0'))
{
if (!(sdtp && sdtp->aflag))
vers_ts->options = xstrdup (entdata->options);
}
vers_ts->entdata = entdata;
}
/*
* -k options specified on the command line override (and overwrite)
* options stored in the entries file
*/
if (options)
vers_ts->options = xstrdup (options);
else if (sdtp && sdtp->aflag == 0)
{
if (!vers_ts->options)
vers_ts->options = xstrdup (sdtp->options);
}
if (!vers_ts->options)
vers_ts->options = xstrdup ("");
/*
* if tags were specified on the command line, they override what is in
* the Entries file
*/
if (tag || date)
{
vers_ts->tag = xstrdup (tag);
vers_ts->date = xstrdup (date);
}
else if (!vers_ts->entdata && (sdtp && sdtp->aflag == 0))
{
if (!vers_ts->tag)
vers_ts->tag = xstrdup (sdtp->tag);
if (!vers_ts->date)
vers_ts->date = xstrdup (sdtp->date);
}
/* Now look up the info on the source controlled file */
if (xfiles != (List *) NULL)
{
p = findnode (xfiles, user);
if (p != NULL)
{
rcsdata = (RCSNode *) p->data;
rcsdata->refcount++;
}
else
rcsdata = NULL;
}
else
rcsdata = RCS_parse (user, repository);
if (rcsdata != NULL)
{
/* squirrel away the rcsdata pointer for others */
vers_ts->srcfile = rcsdata;
/* get RCS version number into vn_rcs (if appropriate) */
if (((vers_ts->tag || vers_ts->date) && force_tag_match) ||
((rcsdata->flags & VALID) && (rcsdata->flags & INATTIC) == 0))
{
if (vers_ts->tag && strcmp (vers_ts->tag, TAG_BASE) == 0)
vers_ts->vn_rcs = xstrdup (vers_ts->vn_user);
else
vers_ts->vn_rcs = RCS_getversion (rcsdata, vers_ts->tag,
vers_ts->date, force_tag_match);
}
/*
* If the source control file exists and has the requested revision,
* get the Date the revision was checked in. If "user" exists, set
* its mtime.
*/
if (set_time)
{
struct utimbuf t;
if (vers_ts->vn_rcs &&
(t.actime = t.modtime = RCS_getrevtime (rcsdata, vers_ts->vn_rcs,
(char *) 0, 0)) != -1)
(void) utime (user, &t);
}
}
/* get user file time-stamp in ts_user */
if (entries != (List *) NULL)
vers_ts->ts_user = time_stamp (user);
return (vers_ts);
}
/*
* Gets the time-stamp for the file "file" and returns it in space it
* allocates
*/
char *
time_stamp (file)
char *file;
{
struct stat sb;
char *cp;
char *ts;
if (stat (file, &sb) < 0)
{
ts = NULL;
}
else
{
ts = xmalloc (51); /* 51 = 2 ctime strings + NULL */
cp = ctime (&sb.st_ctime); /* copy in the create time */
cp[24] = ' ';
(void) strcpy (ts, cp);
cp = ctime (&sb.st_mtime); /* copy in the modify time */
cp[24] = '\0';
(void) strcat (ts, cp);
}
return (ts);
}
/*
* free up a Vers_TS struct
*/
void
freevers_ts (versp)
Vers_TS **versp;
{
if ((*versp)->srcfile)
freercsnode (&((*versp)->srcfile));
if ((*versp)->vn_user)
free ((*versp)->vn_user);
if ((*versp)->vn_rcs)
free ((*versp)->vn_rcs);
if ((*versp)->ts_user)
free ((*versp)->ts_user);
if ((*versp)->ts_rcs)
free ((*versp)->ts_rcs);
if ((*versp)->options)
free ((*versp)->options);
if ((*versp)->tag)
free ((*versp)->tag);
if ((*versp)->date)
free ((*versp)->date);
free ((char *) *versp);
*versp = (Vers_TS *) NULL;
}

View File

@ -0,0 +1,11 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* version.c - the CVS version number
*/
char *version_string = "\nConcurrent Versions System (CVS) 1.3\n";

1073
gnu/usr.bin/cvs/doc/cvs.ms Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
#
# commitinfo,v 1.2 1992/03/31 04:19:47 berliner Exp
#
# The "commitinfo" file is used to control pre-commit checks.
# The filter on the right is invoked with the repository and a list
# of files to check. A non-zero exit of the filter program will
# cause the commit to be aborted.
#
# The first entry on a line is a regular expression which is tested
# against the directory that the change is being committed to, relative to the
# $CVSROOT. If a match is found, then the remainder of the line is the
# name of the filter to run.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name ALL appears as a regular expression it is always used
# in addition to the first matching regex or DEFAULT.
#
^cvs checkforcvsid
DEFAULT checkforid

View File

@ -0,0 +1,30 @@
#
# editinfo,v 1.1 1992/03/21 06:49:39 berliner Exp
#
# The "editinfo" file is used to allow verification of logging
# information. It works best when a template (as specified in the
# rcsinfo file) is provided for the logging procedure. Given a
# template with locations for, a bug-id number, a list of people who
# reviewed the code before it can be checked in, and an external
# process to catalog the differences that were code reviewed, the
# following test can be applied to the code:
#
# Making sure that the entered bug-id number is correct.
# Validating that the code that was reviewed is indeed the code being
# checked in (using the bug-id number or a seperate review
# number to identify this particular code set.).
#
# If any of the above test failed, then the commit would be aborted.
#
# Actions such as mailing a copy of the report to each reviewer are
# better handled by an entry in the loginfo file.
#
# Although these test could be handled by an interactive script being
# called via an entry in commitinfo, The information reported in
# such a script can't be easily merged into the report.
#
# One thing that should be noted is the the ALL keyword is not
# supported. There can be only one entry that matches a given
# repository.
#
DEFAULT $CVSROOT/CVSROOT/edit "%s"

View File

@ -0,0 +1,20 @@
#
# @(#)loginfo 1.5 92/03/31
#
# The "loginfo" file is used to control where "cvs commit" log information
# is sent. The first entry on a line is a regular expression which is tested
# against the directory that the change is being made to, relative to the
# $CVSROOT. If a match is found, then the remainder of the line is a filter
# program that should expect log information on its standard input.
#
# The filter program may use one and only one % modifier (ala printf). If
# %s is specified in the filter program, a brief title is included (enclosed
# in single quotes) showing the modified file names.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name ALL appears as a regular expression it is always used
# in addition to the first matching regex or DEFAULT.
#
DEFAULT $CVSROOT/CVSROOT/log.pl %s $CVSROOT/CVSROOT/commitlog

View File

@ -0,0 +1,566 @@
#
# CVS Modules file for Prisma sources
# @(#)modules 1.5 92/03/31
#
# Three different line formats are valid:
# key -a aliases...
# key [options] directory
# key [options] directory files...
#
# Where "options" are composed of:
# -i prog Run "prog" on "cvs commit" from top-level of module.
# -o prog Run "prog" on "cvs checkout" of module.
# -t prog Run "prog" on "cvs rtag" of module.
# -u prog Run "prog" on "cvs update" of module.
# -d dir Place module in directory "dir" instead of module name.
# -l Top-level directory only -- do not recurse.
#
# And "directory" is a path to a directory relative to $CVSROOT.
#
# The "-a" option specifies an alias. An alias is interpreted as if
# everything on the right of the "-a" had been typed on the command line.
#
# You can encode a module within a module by using the special '&'
# character to interpose another module into the current module. This
# can be useful for creating a module that consists of many directories
# spread out over the entire source repository.
#
# Convenient aliases
world -a .
kernel -a sys lang/adb sparcsim
# CVSROOT support
CVSROOT -i /usr/local/bin/mkmodules CVSROOT
modules -i /usr/local/bin/mkmodules CVSROOT modules
loginfo -i /usr/local/bin/mkmodules CVSROOT loginfo
commitinfo -i /usr/local/bin/mkmodules CVSROOT commitinfo
rcsinfo -i /usr/local/bin/mkmodules CVSROOT rcsinfo
# The "sys" entry exists only to make symbolic links after checkout
sys -o sys/tools/make_links sys
# Sub-directories of "bin"
awk bin/awk
csh bin/csh
diff bin/diff
make bin/make
sed bin/sed
sh bin/sh
# Programs that live in "bin"
cat bin Makefile cat.c
chgrp bin Makefile chgrp.c
chmod bin Makefile chmod.c
cmp bin Makefile cmp.c
cp bin Makefile cp.c
date bin Makefile date.c
dd bin Makefile dd.c
df bin Makefile df.c
domainname bin Makefile domainname.c
du bin Makefile du.c
echo bin Makefile echo.c
ed bin Makefile ed.c
env bin Makefile env.c
expr bin Makefile expr.c
grep bin Makefile grep.c
hostid bin Makefile hostid.c
hostname bin Makefile hostname.c
kill bin Makefile kill.c
ldd bin Makefile ldd.c
line bin Makefile line.c
ln bin Makefile ln.c
login bin Makefile login.c
ls bin Makefile ls.c
mail bin Makefile mail.c
mkdir bin Makefile mkdir.c
mt bin Makefile mt.c
mv bin Makefile mv.c
newgrp bin Makefile newgrp.c
nice bin Makefile nice.c
od bin Makefile od.c
pagesize bin Makefile pagesize.c
passwd bin Makefile passwd.c
pr bin Makefile pr.c
ps bin Makefile ps.c
pwd bin Makefile pwd.c
rm bin Makefile rm.c
rmail bin Makefile rmail.c
rmdir bin Makefile rmdir.c
stty bin Makefile stty.c
su bin Makefile su.c
sync bin Makefile sync.c
tar bin Makefile tar.c
tee bin Makefile tee.c
test bin Makefile test.c
time bin Makefile time.c
wall bin Makefile wall.c
who bin Makefile who.c
write bin Makefile write.c
# Sub-directories of "etc"
dump etc/dump
files etc/files
fsck etc/fsck
getty etc/getty
in.routed etc/in.routed
restore etc/restore
rpc.lockd etc/rpc.lockd
rpc.statd etc/rpc.statd
# Programs that live in "etc"
arp etc Makefile arp.c
biod etc Makefile biod.c
chown etc Makefile chown.c
clri etc Makefile clri.c
dkinfo etc Makefile dkinfo.c
dmesg etc Makefile dmesg.c
fsirand etc Makefile fsirand.c
halt etc Makefile halt.c
ifconfig etc Makefile ifconfig.c
in.rlogind etc Makefile in.rlogind.c
in.rshd etc Makefile in.rshd.c
inetd etc Makefile inetd.c
init etc Makefile init.c
mkfs etc Makefile mkfs.c
mknod etc Makefile mknod.c
mount etc Makefile mount.c
newfs etc Makefile newfs.c
nfsd etc Makefile nfsd.c
portmap etc Makefile portmap.c
pstat etc Makefile pstat.c
reboot etc Makefile reboot.c
renice etc Makefile renice.c
rmt etc Makefile rmt.c
shutdown etc Makefile shutdown.c
syslogd etc Makefile syslogd.c
umount etc Makefile umount.c
update etc Makefile update.c
vipw etc Makefile vipw.c
ypbind etc Makefile ypbind.c
# Sub-directories of "games"
adventure games/adventure
backgammon games/backgammon
battlestar games/battlestar
boggle games/boggle
chess games/chess
ching games/ching
cribbage games/cribbage
fortune games/fortune
hack games/hack
hangman games/hangman
hunt games/hunt
life games/life
mille games/mille
monop games/monop
quiz games/quiz
robots games/robots
sail games/sail
snake games/snake
trek games/trek
# Programs that live in "games"
arithmetic games Makefile arithmetic.c
banner games Makefile banner.c
bcd games Makefile bcd.c
bj games Makefile bj.c
btlgammon games Makefile btlgammon.c
canfield games Makefile canfield.c
cfscores games Makefile cfscores.c
craps games Makefile craps.c
factor games Makefile factor.c
fish games Makefile fish.c
moo games Makefile moo.c
number games Makefile number.c
primes games Makefile primes.c
rain games Makefile rain.c
random games Makefile random.c
worm games Makefile worm.c
worms games Makefile worms.c
wump games Makefile wump.c
# Sub-directories of "lang"
adb lang/adb
as lang/as
boot lang/boot
c2 lang/c2
cgrdr lang/cgrdr
compile lang/compile
cpp lang/cpp
dbx lang/dbx
f77 lang/f77
inline lang/inline
iropt lang/iropt
ld lang/ld
lint lang/lint
m4 lang/m4
pascal lang/pascal
pcc lang/pcc
ratfor lang/ratfor
rtld lang/rtld
tcov lang/tcov
vroot lang/vroot
# Programs that live in "lang"
ar lang Makefile ar.c
nm lang Makefile nm.c
ranlib lang Makefile ranlib.c
size lang Makefile size.c
strip lang Makefile strip.c
symorder lang Makefile symorder.c
# Sub-directories of "lib"
csu lib/csu
libc lib/libc
# Programs that live in "lib"
# NONE
# Sub-directories of "lib/libc"
libc_compat lib/libc/compat
libc_crt lib/libc/crt
libc_des lib/libc/des
libc_gen lib/libc/gen
libc_net lib/libc/net
libc_inet lib/libc/inet
libc_rpc lib/libc/rpc
libc_stdio lib/libc/stdio
libc_sun lib/libc/sun
libc_sys lib/libc/sys
libc_yp lib/libc/yp
# Programs that live in "lib/libc"
# NONE
#Sub-directories of "local"
notes local/notes
# Sub-directories of "man"
man1 man/man1
man2 man/man2
man3 man/man3
man4 man/man4
man5 man/man5
man6 man/man6
man7 man/man7
man8 man/man8
manl man/manl
# Programs that live in "man"
# NONE
# Sub-directories of "old"
old_compact old/compact
old_eyacc old/eyacc
old_filemerge old/filemerge
old_make old/make
# Programs that live in "old"
old_analyze old Makefile analyze.c
old_prmail old Makefile prmail.c
old_pti old Makefile pti.c
old_syslog old Makefile syslog.c
# Sub-directories of "ucb"
Mail ucb/Mail
compress ucb/compress
error ucb/error
ex ucb/ex
ftp ucb/ftp
gprof ucb/gprof
indent ucb/indent
lpr ucb/lpr
more ucb/more
msgs ucb/msgs
netstat ucb/netstat
rdist ucb/rdist
talk ucb/talk
tftp ucb/tftp
tset ucb/tset
vgrind ucb/vgrind
# Programs that live in "ucb"
biff ucb Makefile biff.c
checknr ucb Makefile checknr.c
clear ucb Makefile clear.c
colcrt ucb Makefile colcrt.c
colrm ucb Makefile colrm.c
ctags ucb Makefile ctags.c
expand ucb Makefile expand.c
finger ucb Makefile finger.c
fold ucb Makefile fold.c
from ucb Makefile from.c
fsplit ucb Makefile fsplit.c
gcore ucb Makefile gcore.c
groups ucb Makefile groups.c
head ucb Makefile head.c
last ucb Makefile last.c
lastcomm ucb Makefile lastcomm.c
leave ucb Makefile leave.c
logger ucb Makefile logger.c
man_prog ucb Makefile man.c
mkstr ucb Makefile mkstr.c
printenv ucb Makefile printenv.c
quota ucb Makefile quota.c
rcp ucb Makefile rcp.c
rdate ucb Makefile rdate.c
rlogin ucb Makefile rlogin.c
rsh ucb Makefile rsh.c
rup ucb Makefile rup.c
ruptime ucb Makefile ruptime.c
rusers ucb Makefile rusers.c
rwho ucb Makefile rwho.c
sccs ucb Makefile sccs.c
script ucb Makefile script.c
soelim ucb Makefile soelim.c
strings ucb Makefile strings.c
tail ucb Makefile tail.c
tcopy ucb Makefile tcopy.c
telnet ucb Makefile telnet.c
ul ucb Makefile ul.c
unexpand ucb Makefile unexpand.c
unifdef ucb Makefile unifdef.c
users ucb Makefile users.c
vmstat ucb Makefile vmstat.c
w ucb Makefile w.c
wc ucb Makefile wc.c
what ucb Makefile what.c
whatis ucb Makefile whatis.c
whereis ucb Makefile whereis.c
whoami ucb Makefile whoami.c
whois ucb Makefile whois.c
xstr ucb Makefile xstr.c
yes ucb Makefile yes.c
# Sub-directories of "usr.bin"
calendar usr.bin/calendar
cflow usr.bin/cflow
ctrace usr.bin/ctrace
cxref usr.bin/cxref
dc usr.bin/dc
des usr.bin/des
diff3 usr.bin/diff3
sun_eqn usr.bin/eqn
file usr.bin/file
find usr.bin/find
graph usr.bin/graph
lex usr.bin/lex
sun_neqn usr.bin/neqn
sun_nroff usr.bin/nroff
sun_plot usr.bin/plot
prof usr.bin/prof
refer usr.bin/refer
rpcgen usr.bin/rpcgen
spell usr.bin/spell
sun_tbl usr.bin/tbl
tip usr.bin/tip
trace usr.bin/trace
sun_troff usr.bin/troff
uucp usr.bin/uucp
xsend usr.bin/xsend
yacc usr.bin/yacc
# Programs that live in "usr.bin"
basename usr.bin Makefile basename.c
bc usr.bin Makefile bc.c
cal usr.bin Makefile cal.c
cb usr.bin Makefile cb.c
checkeq usr.bin Makefile checkeq.c
chkey usr.bin Makefile chkey.c
click usr.bin Makefile click.c
col usr.bin Makefile col.c
comm usr.bin Makefile comm.c
cpio usr.bin Makefile cpio.c
crypt usr.bin Makefile crypt.c
csplit usr.bin Makefile csplit.c
cut usr.bin Makefile cut.c
deroff usr.bin Makefile deroff.c
egrep usr.bin Makefile egrep.c
fgrep usr.bin Makefile fgrep.c
getopt usr.bin Makefile getopt.c
id usr.bin Makefile id.c
installcmd usr.bin Makefile installcmd.c
iostat usr.bin Makefile iostat.c
ipcrm usr.bin Makefile ipcrm.c
ipcs usr.bin Makefile ipcs.c
join usr.bin Makefile join.c
keylogin usr.bin Makefile keylogin.c
logname usr.bin Makefile logname.c
look usr.bin Makefile look.c
mesg usr.bin Makefile mesg.c
nl usr.bin Makefile nl.c
pack usr.bin Makefile pack.c
paste usr.bin Makefile paste.c
ptx usr.bin Makefile ptx.c
rev usr.bin Makefile rev.c
screenblank usr.bin Makefile screenblank.c
sdiff usr.bin Makefile sdiff.c
sleep usr.bin Makefile sleep.c
sort usr.bin Makefile sort.c
spline usr.bin Makefile spline.c
split usr.bin Makefile split.c
sum usr.bin Makefile sum.c
touch usr.bin Makefile touch.c
tr usr.bin Makefile tr.c
tsort usr.bin Makefile tsort.c
tty usr.bin Makefile tty.c
uniq usr.bin Makefile uniq.c
units usr.bin Makefile units.c
unpack usr.bin Makefile unpack.c
xargs usr.bin Makefile xargs.c
ypcat usr.bin Makefile ypcat.c
ypmatch usr.bin Makefile ypmatch.c
yppasswd usr.bin Makefile yppasswd.c
ypwhich usr.bin Makefile ypwhich.c
# Sub-directories of "usr.etc"
automount usr.etc/automount
c2convert usr.etc/c2convert
config usr.etc/config
cron usr.etc/cron
eeprom usr.etc/eeprom
etherfind usr.etc/etherfind
format usr.etc/format
htable usr.etc/htable
implog usr.etc/implog
in.ftpd -a usr.etc/in.ftpd ucb/ftp
in.named usr.etc/in.named
in.rwhod usr.etc/in.rwhod
keyserv usr.etc/keyserv
ndbootd usr.etc/ndbootd
praudit usr.etc/praudit
rexd usr.etc/rexd
rpc.bootparamd usr.etc/rpc.bootparamd
termcap usr.etc/termcap
upgrade usr.etc/upgrade
yp usr.etc/yp
zic usr.etc/zic
# Programs that live in "usr.etc"
ac usr.etc Makefile ac.c
accton usr.etc Makefile accton.c
audit usr.etc Makefile audit.c
auditd usr.etc Makefile auditd.c
catman usr.etc Makefile catman.c
chroot usr.etc Makefile chroot.c
dcheck usr.etc Makefile dcheck.c
devnm usr.etc Makefile devnm.c
dumpfs usr.etc Makefile dumpfs.c
edquota usr.etc Makefile edquota.c
exportfs usr.etc Makefile exportfs.c
foption usr.etc Makefile foption.c
gettable usr.etc Makefile gettable.c
grpck usr.etc Makefile grpck.c
icheck usr.etc Makefile icheck.c
in.comsat usr.etc Makefile in.comsat.c
in.fingerd usr.etc Makefile in.fingerd.c
in.rexecd usr.etc Makefile in.rexecd.c
in.telnetd usr.etc Makefile in.telnetd.c
in.tnamed usr.etc Makefile in.tnamed.c
kgmon usr.etc Makefile kgmon.c
link usr.etc Makefile link.c
mkfile usr.etc Makefile mkfile.c
mkproto usr.etc Makefile mkproto.c
mount_lo usr.etc Makefile mount_lo.c
ncheck usr.etc Makefile ncheck.c
nfsstat usr.etc Makefile nfsstat.c
ping usr.etc Makefile ping.c
pwck usr.etc Makefile pwck.c
quot usr.etc Makefile quot.c
quotacheck usr.etc Makefile quotacheck.c
quotaon usr.etc Makefile quotaon.c
rarpd usr.etc Makefile rarpd.c
repquota usr.etc Makefile repquota.c
route usr.etc Makefile route.c
rpc.etherd usr.etc Makefile rpc.etherd.c
rpc.mountd usr.etc Makefile rpc.mountd.c
rpc.pwdauthd usr.etc Makefile rpc.pwdauthd.c
rpc.rquotad usr.etc Makefile rpc.rquotad.c
rpc.rstatd usr.etc Makefile rpc.rstatd.c
rpc.rusersd usr.etc Makefile rpc.rusersd.c
rpc.rwalld usr.etc Makefile rpc.rwalld.c
rpc.sprayd usr.etc Makefile rpc.sprayd.c
rpc.yppasswdd usr.etc Makefile rpc.yppasswdd.c
rpc.ypupdated usr.etc Makefile rpc.ypupdated.c
rpcinfo usr.etc Makefile rpcinfo.c
rwall usr.etc Makefile rwall.c
sa usr.etc Makefile sa.c
savecore usr.etc Makefile savecore.c
showmount usr.etc Makefile showmount.c
spray usr.etc Makefile spray.c
swapon usr.etc Makefile swapon.c
trpt usr.etc Makefile trpt.c
tunefs usr.etc Makefile tunefs.c
unlink usr.etc Makefile unlink.c
# Sub-directories of "usr.lib"
bb_count usr.lib/bb_count
fixedwidthfonts usr.lib/fixedwidthfonts
libcurses usr.lib/libcurses
libdbm usr.lib/libdbm
libg usr.lib/libg
libkvm usr.lib/libkvm
libln usr.lib/libln
liblwp usr.lib/liblwp
libm usr.lib/libm
libmp usr.lib/libmp
libpixrect usr.lib/libpixrect
libplot usr.lib/libplot
libresolv usr.lib/libresolv
librpcsvc usr.lib/librpcsvc
libtermlib usr.lib/libtermlib
liby usr.lib/liby
me usr.lib/me
ms usr.lib/ms
sendmail usr.lib/sendmail
sun_tmac usr.lib/tmac
vfont usr.lib/vfont
# Programs that live in "usr.lib"
getNAME usr.lib Makefile getNAME
makekey usr.lib Makefile makekey
# Sub-directories of "5bin"
5diff3 5bin/diff3
5m4 5bin/m4
# Sub-directories of "5bin", but use sources from other places
5cxref -a 5bin/cxref usr.bin/cxref
5sed -a 5bin/sed bin/sed
5lint -a 5bin/lint lang/pcc lang/lint
# Programs that live in "5bin"
5banner 5bin Makefile banner.c
5cat 5bin Makefile cat.c
5du 5bin Makefile du.c
5echo 5bin Makefile echo.c
5expr 5bin Makefile expr.c
5ls 5bin Makefile ls.c
5nohup 5bin Makefile nohup.c
5od 5bin Makefile od.c
5pg 5bin Makefile pg.c
5pr 5bin Makefile pr.c
5sum 5bin Makefile sum.c
5tabs 5bin Makefile tabs.c
5time 5bin Makefile time.c
5tr 5bin Makefile tr.c
5uname 5bin Makefile uname.c
# Programs that live in "5bin", but use sources from other places
5chmod -a 5bin/Makefile bin/chmod.c
5date -a 5bin/Makefile bin/date.c
5grep -a 5bin/Makefile bin/grep.c
5stty -a 5bin/Makefile bin/stty.c
5col -a 5bin/Makefile usr.bin/col.c
5sort -a 5bin/Makefile usr.bin/sort.c
5touch -a 5bin/Makefile usr.bin/touch.c
# Sub-directories of "5lib"
5compile 5lib/compile
5libcurses 5lib/libcurses
5liby 5lib/liby
5terminfo 5lib/terminfo
# Programs that live in "5lib"
# NONE

View File

@ -0,0 +1,18 @@
#
# rcsinfo,v 1.3 1992/04/10 18:59:14 berliner Exp
#
# The "rcsinfo" file is used to control templates with which the editor
# is invoked on commit and import.
#
# The first entry on a line is a regular expression which is tested
# against the directory that the change is being made to, relative to the
# $CVSROOT. If a match is found, then the remainder of the line is the
# name of the file that contains the template.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name ALL appears as a regular expression it is always used
# in addition to the first matching regex or DEFAULT.
#
DEFAULT /src/master/CVSROOT/rcstemplate

View File

@ -0,0 +1,8 @@
LIB = cvs
CFLAGS += -I${.CURDIR} -I${.CURDIR}/../cvs -DFTIME_MISSING -DHAVE_TIMEZONE
SRCS = argmatch.c error.c getopt.c sighandle.c strippath.c stripslash.c yesno.c \
getdate.y fnmatch.c regex.c subr.c myndbm.c hash.c
.include <bsd.lib.mk>

View File

@ -0,0 +1,91 @@
# Makefile for library files used by GNU CVS.
# Do not use this makefile directly, but only from `../Makefile'.
# Copyright (C) 1986, 1988-1992 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# @(#)Makefile.in 1.12 92/03/31
SHELL = /bin/sh
srcdir = @srcdir@
@VPATH@
SOURCES = argmatch.c \
error.c getopt.c getopt1.c \
sighandle.c \
strippath.c stripslash.c yesno.c \
getdate.y \
hostname.c fnmatch.c ftruncate.c mkdir.c rename.c regex.c \
strdup.c getwd.c alloca.c
OBJECTS = argmatch.o \
error.o getopt.o getopt1.o \
sighandle.o \
strippath.o stripslash.o yesno.o \
getdate.o \
@LIBOBJS@
DISTFILES = Makefile.in getopt.h \
fnmatch.h regex.h system.h wait.h $(SOURCES)
xxx:
@cd ..; $(MAKE) all SUBDIRS=lib
all: libcvs.a
.PHONY: all
install: all
.PHONY: install
tags: $(DISTFILES)
ctags $(DISTFILES)
TAGS: $(DISTFILES)
etags $(DISTFILES)
ls:
@echo $(DISTFILES)
.PHONY: ls
clean:
rm -f *.a *.o *.tab.c getdate.c
.PHONY: clean
distclean: clean
rm -f tags TAGS Makefile
.PHONY: distclean
realclean: distclean
.PHONY: realclean
dist:
ln $(DISTFILES) ../`cat ../.fname`/lib
.PHONY: dist
libcvs.a: $(OBJECTS)
$(AR) cr $@ $(OBJECTS)
-$(RANLIB) $@
getdate.c: getdate.y
@echo expect 8 shift/reduce conflicts
$(YACC) $(srcdir)/getdate.y
-if test -f y.tab.c ; then mv y.tab.c getdate.c ; fi
-if test -f getdate.tab.c ; then mv getdate.tab.c getdate.c ; fi
fnmatch.o: fnmatch.h
getopt1.o: getopt.h
regex.o: regex.h
getwd.o: system.h

View File

@ -0,0 +1,191 @@
/*
alloca -- (mostly) portable public-domain implementation -- D A Gwyn
last edit: 86/05/30 rms
include config.h, since on VMS it renames some symbols.
Use xmalloc instead of malloc.
This implementation of the PWB library alloca() function,
which is used to allocate space off the run-time stack so
that it is automatically reclaimed upon procedure exit,
was inspired by discussions with J. Q. Johnson of Cornell.
It should work under any C implementation that uses an
actual procedure stack (as opposed to a linked list of
frames). There are some preprocessor constants that can
be defined when compiling for your specific system, for
improved efficiency; however, the defaults should be okay.
The general concept of this implementation is to keep
track of all alloca()-allocated blocks, and reclaim any
that are found to be deeper in the stack than the current
invocation. This heuristic does not reclaim storage as
soon as it becomes invalid, but it will do so eventually.
As a special case, alloca(0) reclaims storage without
allocating any. It is a good idea to use alloca(0) in
your main control loop, etc. to force garbage collection.
*/
#ifndef lint
static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */
#endif
#ifdef emacs
#include "config.h"
#ifdef static
/* actually, only want this if static is defined as ""
-- this is for usg, in which emacs must undefine static
in order to make unexec workable
*/
#ifndef STACK_DIRECTION
you
lose
-- must know STACK_DIRECTION at compile-time
#endif /* STACK_DIRECTION undefined */
#endif /* static */
#endif /* emacs */
#if __STDC__
typedef void *pointer; /* generic pointer type */
#else
typedef char *pointer; /* generic pointer type */
#endif
#define NULL 0 /* null pointer constant */
extern void free();
extern pointer xmalloc();
/*
Define STACK_DIRECTION if you know the direction of stack
growth for your system; otherwise it will be automatically
deduced at run-time.
STACK_DIRECTION > 0 => grows toward higher addresses
STACK_DIRECTION < 0 => grows toward lower addresses
STACK_DIRECTION = 0 => direction of growth unknown
*/
#ifndef STACK_DIRECTION
#define STACK_DIRECTION 0 /* direction unknown */
#endif
#if STACK_DIRECTION != 0
#define STACK_DIR STACK_DIRECTION /* known at compile-time */
#else /* STACK_DIRECTION == 0; need run-time code */
static int stack_dir; /* 1 or -1 once known */
#define STACK_DIR stack_dir
static void
find_stack_direction (/* void */)
{
static char *addr = NULL; /* address of first
`dummy', once known */
auto char dummy; /* to get stack address */
if (addr == NULL)
{ /* initial entry */
addr = &dummy;
find_stack_direction (); /* recurse once */
}
else /* second entry */
if (&dummy > addr)
stack_dir = 1; /* stack grew upward */
else
stack_dir = -1; /* stack grew downward */
}
#endif /* STACK_DIRECTION == 0 */
/*
An "alloca header" is used to:
(a) chain together all alloca()ed blocks;
(b) keep track of stack depth.
It is very important that sizeof(header) agree with malloc()
alignment chunk size. The following default should work okay.
*/
#ifndef ALIGN_SIZE
#define ALIGN_SIZE sizeof(double)
#endif
typedef union hdr
{
char align[ALIGN_SIZE]; /* to force sizeof(header) */
struct
{
union hdr *next; /* for chaining headers */
char *deep; /* for stack depth measure */
} h;
} header;
/*
alloca( size ) returns a pointer to at least `size' bytes of
storage which will be automatically reclaimed upon exit from
the procedure that called alloca(). Originally, this space
was supposed to be taken from the current stack frame of the
caller, but that method cannot be made to work for some
implementations of C, for example under Gould's UTX/32.
*/
static header *last_alloca_header = NULL; /* -> last alloca header */
pointer
alloca (size) /* returns pointer to storage */
unsigned size; /* # bytes to allocate */
{
auto char probe; /* probes stack depth: */
register char *depth = &probe;
#if STACK_DIRECTION == 0
if (STACK_DIR == 0) /* unknown growth direction */
find_stack_direction ();
#endif
/* Reclaim garbage, defined as all alloca()ed storage that
was allocated from deeper in the stack than currently. */
{
register header *hp; /* traverses linked list */
for (hp = last_alloca_header; hp != NULL;)
if (STACK_DIR > 0 && hp->h.deep > depth
|| STACK_DIR < 0 && hp->h.deep < depth)
{
register header *np = hp->h.next;
free ((pointer) hp); /* collect garbage */
hp = np; /* -> next header */
}
else
break; /* rest are not deeper */
last_alloca_header = hp; /* -> last valid storage */
}
if (size == 0)
return NULL; /* no allocation required */
/* Allocate combined header + user data storage. */
{
register pointer new = xmalloc (sizeof (header) + size);
/* address of header */
((header *)new)->h.next = last_alloca_header;
((header *)new)->h.deep = depth;
last_alloca_header = (header *)new;
/* User storage begins just after header. */
return (pointer)((char *)new + sizeof(header));
}
}

View File

@ -0,0 +1,83 @@
/* argmatch.c -- find a match for a string in an array
Copyright (C) 1990 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by David MacKenzie <djm@ai.mit.edu> */
#include <stdio.h>
#ifdef STDC_HEADERS
#include <string.h>
#endif
extern char *program_name;
/* If ARG is an unambiguous match for an element of the
null-terminated array OPTLIST, return the index in OPTLIST
of the matched element, else -1 if it does not match any element
or -2 if it is ambiguous (is a prefix of more than one element). */
int
argmatch (arg, optlist)
char *arg;
char **optlist;
{
int i; /* Temporary index in OPTLIST. */
int arglen; /* Length of ARG. */
int matchind = -1; /* Index of first nonexact match. */
int ambiguous = 0; /* If nonzero, multiple nonexact match(es). */
arglen = strlen (arg);
/* Test all elements for either exact match or abbreviated matches. */
for (i = 0; optlist[i]; i++)
{
if (!strncmp (optlist[i], arg, arglen))
{
if (strlen (optlist[i]) == arglen)
/* Exact match found. */
return i;
else if (matchind == -1)
/* First nonexact match found. */
matchind = i;
else
/* Second nonexact match found. */
ambiguous = 1;
}
}
if (ambiguous)
return -2;
else
return matchind;
}
/* Error reporting for argmatch.
KIND is a description of the type of entity that was being matched.
VALUE is the invalid value that was given.
PROBLEM is the return value from argmatch. */
void
invalid_arg (kind, value, problem)
char *kind;
char *value;
int problem;
{
fprintf (stderr, "%s: ", program_name);
if (problem == -1)
fprintf (stderr, "invalid");
else /* Assume -2. */
fprintf (stderr, "ambiguous");
fprintf (stderr, " %s `%s'\n", kind, value);
}

View File

@ -0,0 +1,36 @@
/*
dup2 -- 7th Edition UNIX system call emulation for UNIX System V
last edit: 11-Feb-1987 D A Gwyn
*/
#include <errno.h>
#include <fcntl.h>
extern int close(), fcntl();
int
dup2( oldfd, newfd )
int oldfd; /* already-open file descriptor */
int newfd; /* desired duplicate descriptor */
{
register int ret; /* for fcntl() return value */
register int save; /* for saving entry errno */
if ( oldfd == newfd )
return oldfd; /* be careful not to close() */
save = errno; /* save entry errno */
(void) close( newfd ); /* in case newfd is open */
/* (may have just clobbered the original errno value) */
ret = fcntl( oldfd, F_DUPFD, newfd ); /* dupe it */
if ( ret >= 0 )
errno = save; /* restore entry errno */
else /* fcntl() returned error */
if ( errno == EINVAL )
errno = EBADF; /* we think of everything */
return ret; /* return file descriptor */
}

193
gnu/usr.bin/cvs/lib/error.c Normal file
View File

@ -0,0 +1,193 @@
/* error.c -- error handler for noninteractive utilities
Copyright (C) 1990-1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* David MacKenzie */
/* Brian Berliner added support for CVS */
#ifndef lint
static char rcsid[] = "@(#)error.c 1.9 92/03/31";
#endif /* not lint */
#include <stdio.h>
/* turn on CVS support by default, since this is the CVS distribution */
#define CVS_SUPPORT
#ifdef CVS_SUPPORT
#if __STDC__
void Lock_Cleanup(void);
#else
void Lock_Cleanup();
#endif /* __STDC__ */
#endif /* CVS_SUPPORT */
#ifndef VPRINTF_MISSING
#if __STDC__
#include <stdarg.h>
#define VA_START(args, lastarg) va_start(args, lastarg)
#else
#include <varargs.h>
#define VA_START(args, lastarg) va_start(args)
#endif
#else
#ifndef DOPRNT_MISSING
#define va_alist args
#define va_dcl int args;
#else
#define va_alist a1, a2, a3, a4, a5, a6, a7, a8
#define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
#endif
#endif
#ifdef STDC_HEADERS
#include <stdlib.h>
#include <string.h>
#else
#if __STDC__
void exit(int status);
#else
void exit ();
#endif /* __STDC__ */
#endif
#ifdef STRERROR_MISSING
static char *
strerror (errnum)
int errnum;
{
extern char *sys_errlist[];
extern int sys_nerr;
if (errnum > 0 && errnum < sys_nerr)
return sys_errlist[errnum];
return "Unknown system error";
}
#endif /* STRERROR_MISSING */
/* Print the program name and error message MESSAGE, which is a printf-style
format string with optional args.
If ERRNUM is nonzero, print its corresponding system error message.
Exit with status STATUS if it is nonzero. */
/* VARARGS */
void
#if !defined (VPRINTF_MISSING) && __STDC__
error (int status, int errnum, char *message, ...)
#else
error (status, errnum, message, va_alist)
int status;
int errnum;
char *message;
va_dcl
#endif
{
extern char *program_name;
#ifdef CVS_SUPPORT
extern char *command_name;
#endif
#ifndef VPRINTF_MISSING
va_list args;
#endif
#ifdef CVS_SUPPORT
if (command_name && *command_name)
if (status)
fprintf (stderr, "%s [%s aborted]: ", program_name, command_name);
else
fprintf (stderr, "%s %s: ", program_name, command_name);
else
fprintf (stderr, "%s: ", program_name);
#else
fprintf (stderr, "%s: ", program_name);
#endif
#ifndef VPRINTF_MISSING
VA_START (args, message);
vfprintf (stderr, message, args);
va_end (args);
#else
#ifndef DOPRNT_MISSING
_doprnt (message, &args, stderr);
#else
fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
#endif
#endif
if (errnum)
fprintf (stderr, ": %s", strerror (errnum));
putc ('\n', stderr);
fflush (stderr);
if (status)
{
#ifdef CVS_SUPPORT
Lock_Cleanup();
#endif
exit (status);
}
}
#ifdef CVS_SUPPORT
/* Print the program name and error message MESSAGE, which is a printf-style
format string with optional args to the file specified by FP.
If ERRNUM is nonzero, print its corresponding system error message.
Exit with status STATUS if it is nonzero. */
/* VARARGS */
void
#if !defined (VPRINTF_MISSING) && __STDC__
fperror (FILE *fp, int status, int errnum, char *message, ...)
#else
fperror (fp, status, errnum, message, va_alist)
FILE *fp;
int status;
int errnum;
char *message;
va_dcl
#endif
{
extern char *program_name;
#ifndef VPRINTF_MISSING
va_list args;
#endif
fprintf (fp, "%s: ", program_name);
#ifndef VPRINTF_MISSING
VA_START (args, message);
vfprintf (fp, message, args);
va_end (args);
#else
#ifndef DOPRNT_MISSING
_doprnt (message, &args, fp);
#else
fprintf (fp, message, a1, a2, a3, a4, a5, a6, a7, a8);
#endif
#endif
if (errnum)
fprintf (fp, ": %s", strerror (errnum));
putc ('\n', fp);
fflush (fp);
if (status)
{
#ifdef CVS_SUPPORT
Lock_Cleanup();
#endif
exit (status);
}
}
#endif /* CVS_SUPPORT */

View File

@ -0,0 +1,183 @@
/* Copyright (C) 1992 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA. */
/* Modified slightly by Brian Berliner <berliner@sun.com> for CVS use */
/* IGNORE(@ */
/* #include <ansidecl.h> */
/* @) */
#include <errno.h>
#include <fnmatch.h>
#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
extern int errno;
#endif
#if !__STDC__
#define const
#endif
/* Match STRING against the filename pattern PATTERN, returning zero if
it matches, nonzero if not. */
int
#if __STDC__
fnmatch (const char *pattern, const char *string, int flags)
#else
fnmatch (pattern, string, flags)
char *pattern;
char *string;
int flags;
#endif
{
register const char *p = pattern, *n = string;
register char c;
if ((flags & ~__FNM_FLAGS) != 0)
{
errno = EINVAL;
return -1;
}
while ((c = *p++) != '\0')
{
switch (c)
{
case '?':
if (*n == '\0')
return FNM_NOMATCH;
else if ((flags & FNM_PATHNAME) && *n == '/')
return FNM_NOMATCH;
else if ((flags & FNM_PERIOD) && *n == '.' &&
(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
return FNM_NOMATCH;
break;
case '\\':
if (!(flags & FNM_NOESCAPE))
c = *p++;
if (*n != c)
return FNM_NOMATCH;
break;
case '*':
if ((flags & FNM_PERIOD) && *n == '.' &&
(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
return FNM_NOMATCH;
for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
if (((flags & FNM_PATHNAME) && *n == '/') ||
(c == '?' && *n == '\0'))
return FNM_NOMATCH;
if (c == '\0')
return 0;
{
char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
for (--p; *n != '\0'; ++n)
if ((c == '[' || *n == c1) &&
fnmatch(p, n, flags & ~FNM_PERIOD) == 0)
return 0;
return FNM_NOMATCH;
}
case '[':
{
/* Nonzero if the sense of the character class is inverted. */
register int not;
if (*n == '\0')
return FNM_NOMATCH;
if ((flags & FNM_PERIOD) && *n == '.' &&
(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
return FNM_NOMATCH;
not = (*p == '!' || *p == '^');
if (not)
++p;
c = *p++;
for (;;)
{
register char cstart = c, cend = c;
if (!(flags & FNM_NOESCAPE) && c == '\\')
cstart = cend = *p++;
if (c == '\0')
/* [ (unterminated) loses. */
return FNM_NOMATCH;
c = *p++;
if ((flags & FNM_PATHNAME) && c == '/')
/* [/] can never match. */
return FNM_NOMATCH;
if (c == '-' && *p != ']')
{
cend = *p++;
if (!(flags & FNM_NOESCAPE) && cend == '\\')
cend = *p++;
if (cend == '\0')
return FNM_NOMATCH;
c = *p++;
}
if (*n >= cstart && *n <= cend)
goto matched;
if (c == ']')
break;
}
if (!not)
return FNM_NOMATCH;
break;
matched:;
/* Skip the rest of the [...] that already matched. */
while (c != ']')
{
if (c == '\0')
/* [... (unterminated) loses. */
return FNM_NOMATCH;
c = *p++;
if (!(flags & FNM_NOESCAPE) && c == '\\')
/* 1003.2d11 is unclear if this is right. %%% */
++p;
}
if (not)
return FNM_NOMATCH;
}
break;
default:
if (c != *n)
return FNM_NOMATCH;
}
++n;
}
if (*n == '\0')
return 0;
return FNM_NOMATCH;
}

View File

@ -0,0 +1,45 @@
/* Copyright (C) 1992 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA. */
#ifndef _FNMATCH_H
#define _FNMATCH_H 1
/* Bits set in the FLAGS argument to `fnmatch'. */
#undef FNM_PATHNAME
#define FNM_PATHNAME (1 << 0)/* No wildcard can ever match `/'. */
#undef FNM_NOESCAPE
#define FNM_NOESCAPE (1 << 1)/* Backslashes don't quote special chars. */
#undef FNM_PERIOD
#define FNM_PERIOD (1 << 2)/* Leading `.' is matched only explicitly. */
#undef __FNM_FLAGS
#define __FNM_FLAGS (FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD)
/* Value returned by `fnmatch' if STRING does not match PATTERN. */
#undef FNM_NOMATCH
#define FNM_NOMATCH 1
/* Match STRING against the filename pattern PATTERN,
returning zero if it matches, FNM_NOMATCH if not. */
#if __STDC__
extern int fnmatch (const char *pattern, const char *string, int flags);
#else
extern int fnmatch ();
#endif
#endif /* fnmatch.h */

View File

@ -0,0 +1,72 @@
/* ftruncate emulations that work on some System V's.
This file is in the public domain. */
#include <sys/types.h>
#include <fcntl.h>
#ifdef F_CHSIZE
int
ftruncate (fd, length)
int fd;
off_t length;
{
return fcntl (fd, F_CHSIZE, length);
}
#else
#ifdef F_FREESP
/* The following function was written by
kucharsk@Solbourne.com (William Kucharski) */
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
int
ftruncate (fd, length)
int fd;
off_t length;
{
struct flock fl;
struct stat filebuf;
if (fstat (fd, &filebuf) < 0)
return -1;
if (filebuf.st_size < length)
{
/* Extend file length. */
if (lseek (fd, (length - 1), SEEK_SET) < 0)
return -1;
/* Write a "0" byte. */
if (write (fd, "", 1) != 1)
return -1;
}
else
{
/* Truncate length. */
fl.l_whence = 0;
fl.l_len = 0;
fl.l_start = length;
fl.l_type = F_WRLCK; /* Write lock on file space. */
/* This relies on the UNDOCUMENTED F_FREESP argument to
fcntl, which truncates the file so that it ends at the
position indicated by fl.l_start.
Will minor miracles never cease? */
if (fcntl (fd, F_FREESP, &fl) < 0)
return -1;
}
return 0;
}
#else
int
ftruncate (fd, length)
int fd;
off_t length;
{
return chsize (fd, length);
}
#endif
#endif

View File

@ -0,0 +1,889 @@
%{
/* 1.8
** @(#)getdate.y 1.8 92/03/03
**
** Originally written by Steven M. Bellovin <smb@research.att.com> while
** at the University of North Carolina at Chapel Hill. Later tweaked by
** a couple of people on Usenet. Completely overhauled by Rich $alz
** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
** send any email to Rich.
**
** This grammar has eight shift/reduce conflicts.
**
** This code is in the public domain and has no copyright.
*/
/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */
/* SUPPRESS 288 on yyerrlab *//* Label unused */
#include "system.h"
#include <ctype.h>
#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__)
#ifdef __GNUC__
#undef alloca /* might get redefined below */
#endif
#endif
extern struct tm *localtime();
#define yyparse getdate_yyparse
#define yylex getdate_yylex
#define yyerror getdate_yyerror
#if !defined(lint) && !defined(SABER)
static char RCS[] = "@(#)getdate.y 1.8 92/03/03";
#endif /* !defined(lint) && !defined(SABER) */
#define EPOCH 1970
#define HOUR(x) ((time_t)(x) * 60)
#define SECSPERDAY (24L * 60L * 60L)
/*
** An entry in the lexical lookup table.
*/
typedef struct _TABLE {
char *name;
int type;
time_t value;
} TABLE;
/*
** Daylight-savings mode: on, off, or not yet known.
*/
typedef enum _DSTMODE {
DSTon, DSToff, DSTmaybe
} DSTMODE;
/*
** Meridian: am, pm, or 24-hour style.
*/
typedef enum _MERIDIAN {
MERam, MERpm, MER24
} MERIDIAN;
/*
** Global variables. We could get rid of most of these by using a good
** union as the yacc stack. (This routine was originally written before
** yacc had the %union construct.) Maybe someday; right now we only use
** the %union very rarely.
*/
static char *yyInput;
static DSTMODE yyDSTmode;
static time_t yyDayOrdinal;
static time_t yyDayNumber;
static int yyHaveDate;
static int yyHaveDay;
static int yyHaveRel;
static int yyHaveTime;
static int yyHaveZone;
static time_t yyTimezone;
static time_t yyDay;
static time_t yyHour;
static time_t yyMinutes;
static time_t yyMonth;
static time_t yySeconds;
static time_t yyYear;
static MERIDIAN yyMeridian;
static time_t yyRelMonth;
static time_t yyRelSeconds;
%}
%union {
time_t Number;
enum _MERIDIAN Meridian;
}
%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
%type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE
%type <Meridian> tMERIDIAN o_merid
%%
spec : /* NULL */
| spec item
;
item : time {
yyHaveTime++;
}
| zone {
yyHaveZone++;
}
| date {
yyHaveDate++;
}
| day {
yyHaveDay++;
}
| rel {
yyHaveRel++;
}
| number
;
time : tUNUMBER tMERIDIAN {
yyHour = $1;
yyMinutes = 0;
yySeconds = 0;
yyMeridian = $2;
}
| tUNUMBER ':' tUNUMBER o_merid {
yyHour = $1;
yyMinutes = $3;
yySeconds = 0;
yyMeridian = $4;
}
| tUNUMBER ':' tUNUMBER tSNUMBER {
yyHour = $1;
yyMinutes = $3;
yyMeridian = MER24;
yyDSTmode = DSToff;
yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
}
| tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
yyHour = $1;
yyMinutes = $3;
yySeconds = $5;
yyMeridian = $6;
}
| tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
yyHour = $1;
yyMinutes = $3;
yySeconds = $5;
yyMeridian = MER24;
yyDSTmode = DSToff;
yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
}
;
zone : tZONE {
yyTimezone = $1;
yyDSTmode = DSToff;
}
| tDAYZONE {
yyTimezone = $1;
yyDSTmode = DSTon;
}
|
tZONE tDST {
yyTimezone = $1;
yyDSTmode = DSTon;
}
;
day : tDAY {
yyDayOrdinal = 1;
yyDayNumber = $1;
}
| tDAY ',' {
yyDayOrdinal = 1;
yyDayNumber = $1;
}
| tUNUMBER tDAY {
yyDayOrdinal = $1;
yyDayNumber = $2;
}
;
date : tUNUMBER '/' tUNUMBER {
yyMonth = $1;
yyDay = $3;
}
| tUNUMBER '/' tUNUMBER '/' tUNUMBER {
yyMonth = $1;
yyDay = $3;
yyYear = $5;
}
| tMONTH tUNUMBER {
yyMonth = $1;
yyDay = $2;
}
| tMONTH tUNUMBER ',' tUNUMBER {
yyMonth = $1;
yyDay = $2;
yyYear = $4;
}
| tUNUMBER tMONTH {
yyMonth = $2;
yyDay = $1;
}
| tUNUMBER tMONTH tUNUMBER {
yyMonth = $2;
yyDay = $1;
yyYear = $3;
}
;
rel : relunit tAGO {
yyRelSeconds = -yyRelSeconds;
yyRelMonth = -yyRelMonth;
}
| relunit
;
relunit : tUNUMBER tMINUTE_UNIT {
yyRelSeconds += $1 * $2 * 60L;
}
| tSNUMBER tMINUTE_UNIT {
yyRelSeconds += $1 * $2 * 60L;
}
| tMINUTE_UNIT {
yyRelSeconds += $1 * 60L;
}
| tSNUMBER tSEC_UNIT {
yyRelSeconds += $1;
}
| tUNUMBER tSEC_UNIT {
yyRelSeconds += $1;
}
| tSEC_UNIT {
yyRelSeconds++;
}
| tSNUMBER tMONTH_UNIT {
yyRelMonth += $1 * $2;
}
| tUNUMBER tMONTH_UNIT {
yyRelMonth += $1 * $2;
}
| tMONTH_UNIT {
yyRelMonth += $1;
}
;
number : tUNUMBER {
if (yyHaveTime && yyHaveDate && !yyHaveRel)
yyYear = $1;
else {
if($1>10000) {
time_t date_part;
date_part= $1/10000;
yyHaveDate++;
yyDay= (date_part)%100;
yyMonth= (date_part/100)%100;
yyYear = date_part/10000;
}
yyHaveTime++;
if ($1 < 100) {
yyHour = $1;
yyMinutes = 0;
}
else {
yyHour = $1 / 100;
yyMinutes = $1 % 100;
}
yySeconds = 0;
yyMeridian = MER24;
}
}
;
o_merid : /* NULL */ {
$$ = MER24;
}
| tMERIDIAN {
$$ = $1;
}
;
%%
/* Month and day table. */
static TABLE MonthDayTable[] = {
{ "january", tMONTH, 1 },
{ "february", tMONTH, 2 },
{ "march", tMONTH, 3 },
{ "april", tMONTH, 4 },
{ "may", tMONTH, 5 },
{ "june", tMONTH, 6 },
{ "july", tMONTH, 7 },
{ "august", tMONTH, 8 },
{ "september", tMONTH, 9 },
{ "sept", tMONTH, 9 },
{ "october", tMONTH, 10 },
{ "november", tMONTH, 11 },
{ "december", tMONTH, 12 },
{ "sunday", tDAY, 0 },
{ "monday", tDAY, 1 },
{ "tuesday", tDAY, 2 },
{ "tues", tDAY, 2 },
{ "wednesday", tDAY, 3 },
{ "wednes", tDAY, 3 },
{ "thursday", tDAY, 4 },
{ "thur", tDAY, 4 },
{ "thurs", tDAY, 4 },
{ "friday", tDAY, 5 },
{ "saturday", tDAY, 6 },
{ NULL }
};
/* Time units table. */
static TABLE UnitsTable[] = {
{ "year", tMONTH_UNIT, 12 },
{ "month", tMONTH_UNIT, 1 },
{ "fortnight", tMINUTE_UNIT, 14 * 24 * 60 },
{ "week", tMINUTE_UNIT, 7 * 24 * 60 },
{ "day", tMINUTE_UNIT, 1 * 24 * 60 },
{ "hour", tMINUTE_UNIT, 60 },
{ "minute", tMINUTE_UNIT, 1 },
{ "min", tMINUTE_UNIT, 1 },
{ "second", tSEC_UNIT, 1 },
{ "sec", tSEC_UNIT, 1 },
{ NULL }
};
/* Assorted relative-time words. */
static TABLE OtherTable[] = {
{ "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 },
{ "yesterday", tMINUTE_UNIT, -1 * 24 * 60 },
{ "today", tMINUTE_UNIT, 0 },
{ "now", tMINUTE_UNIT, 0 },
{ "last", tUNUMBER, -1 },
{ "this", tMINUTE_UNIT, 0 },
{ "next", tUNUMBER, 2 },
{ "first", tUNUMBER, 1 },
/* { "second", tUNUMBER, 2 }, */
{ "third", tUNUMBER, 3 },
{ "fourth", tUNUMBER, 4 },
{ "fifth", tUNUMBER, 5 },
{ "sixth", tUNUMBER, 6 },
{ "seventh", tUNUMBER, 7 },
{ "eighth", tUNUMBER, 8 },
{ "ninth", tUNUMBER, 9 },
{ "tenth", tUNUMBER, 10 },
{ "eleventh", tUNUMBER, 11 },
{ "twelfth", tUNUMBER, 12 },
{ "ago", tAGO, 1 },
{ NULL }
};
/* The timezone table. */
/* Some of these are commented out because a time_t can't store a float. */
static TABLE TimezoneTable[] = {
{ "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
{ "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */
{ "utc", tZONE, HOUR( 0) },
{ "wet", tZONE, HOUR( 0) }, /* Western European */
{ "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
{ "wat", tZONE, HOUR( 1) }, /* West Africa */
{ "at", tZONE, HOUR( 2) }, /* Azores */
#if 0
/* For completeness. BST is also British Summer, and GST is
* also Guam Standard. */
{ "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
{ "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
#endif
#if 0
{ "nft", tZONE, HOUR(3.5) }, /* Newfoundland */
{ "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */
{ "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */
#endif
{ "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
{ "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
{ "est", tZONE, HOUR( 5) }, /* Eastern Standard */
{ "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
{ "cst", tZONE, HOUR( 6) }, /* Central Standard */
{ "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
{ "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
{ "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
{ "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
{ "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
{ "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
{ "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
{ "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
{ "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */
{ "cat", tZONE, HOUR(10) }, /* Central Alaska */
{ "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */
{ "nt", tZONE, HOUR(11) }, /* Nome */
{ "idlw", tZONE, HOUR(12) }, /* International Date Line West */
{ "cet", tZONE, -HOUR(1) }, /* Central European */
{ "met", tZONE, -HOUR(1) }, /* Middle European */
{ "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
{ "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
{ "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
{ "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
{ "fwt", tZONE, -HOUR(1) }, /* French Winter */
{ "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
{ "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */
{ "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */
#if 0
{ "it", tZONE, -HOUR(3.5) },/* Iran */
#endif
{ "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
{ "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
#if 0
{ "ist", tZONE, -HOUR(5.5) },/* Indian Standard */
#endif
{ "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
#if 0
/* For completeness. NST is also Newfoundland Stanard, and SST is
* also Swedish Summer. */
{ "nst", tZONE, -HOUR(6.5) },/* North Sumatra */
{ "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */
#endif /* 0 */
{ "wast", tZONE, -HOUR(7) }, /* West Australian Standard */
{ "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */
#if 0
{ "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */
#endif
{ "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */
{ "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */
#if 0
{ "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */
{ "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */
#endif
{ "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
{ "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
{ "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
{ "nzt", tZONE, -HOUR(12) }, /* New Zealand */
{ "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
{ "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
{ "idle", tZONE, -HOUR(12) }, /* International Date Line East */
{ NULL }
};
/* Military timezone table. */
static TABLE MilitaryTable[] = {
{ "a", tZONE, HOUR( 1) },
{ "b", tZONE, HOUR( 2) },
{ "c", tZONE, HOUR( 3) },
{ "d", tZONE, HOUR( 4) },
{ "e", tZONE, HOUR( 5) },
{ "f", tZONE, HOUR( 6) },
{ "g", tZONE, HOUR( 7) },
{ "h", tZONE, HOUR( 8) },
{ "i", tZONE, HOUR( 9) },
{ "k", tZONE, HOUR( 10) },
{ "l", tZONE, HOUR( 11) },
{ "m", tZONE, HOUR( 12) },
{ "n", tZONE, HOUR(- 1) },
{ "o", tZONE, HOUR(- 2) },
{ "p", tZONE, HOUR(- 3) },
{ "q", tZONE, HOUR(- 4) },
{ "r", tZONE, HOUR(- 5) },
{ "s", tZONE, HOUR(- 6) },
{ "t", tZONE, HOUR(- 7) },
{ "u", tZONE, HOUR(- 8) },
{ "v", tZONE, HOUR(- 9) },
{ "w", tZONE, HOUR(-10) },
{ "x", tZONE, HOUR(-11) },
{ "y", tZONE, HOUR(-12) },
{ "z", tZONE, HOUR( 0) },
{ NULL }
};
/* ARGSUSED */
int
yyerror(s)
char *s;
{
return 0;
}
static time_t
ToSeconds(Hours, Minutes, Seconds, Meridian)
time_t Hours;
time_t Minutes;
time_t Seconds;
MERIDIAN Meridian;
{
if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
return -1;
switch (Meridian) {
case MER24:
if (Hours < 0 || Hours > 23)
return -1;
return (Hours * 60L + Minutes) * 60L + Seconds;
case MERam:
if (Hours < 1 || Hours > 12)
return -1;
return (Hours * 60L + Minutes) * 60L + Seconds;
case MERpm:
if (Hours < 1 || Hours > 12)
return -1;
return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
}
/* NOTREACHED */
}
static time_t
Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
time_t Month;
time_t Day;
time_t Year;
time_t Hours;
time_t Minutes;
time_t Seconds;
MERIDIAN Meridian;
DSTMODE DSTmode;
{
static int DaysInMonth[12] = {
31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
time_t tod;
time_t Julian;
int i;
if (Year < 0)
Year = -Year;
if (Year < 100)
Year += 1900;
DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
? 29 : 28;
if (Year < EPOCH || Year > 1999
|| Month < 1 || Month > 12
/* Lint fluff: "conversion from long may lose accuracy" */
|| Day < 1 || Day > DaysInMonth[(int)--Month])
return -1;
for (Julian = Day - 1, i = 0; i < Month; i++)
Julian += DaysInMonth[i];
for (i = EPOCH; i < Year; i++)
Julian += 365 + (i % 4 == 0);
Julian *= SECSPERDAY;
Julian += yyTimezone * 60L;
if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
return -1;
Julian += tod;
if (DSTmode == DSTon
|| (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
Julian -= 60 * 60;
return Julian;
}
static time_t
DSTcorrect(Start, Future)
time_t Start;
time_t Future;
{
time_t StartDay;
time_t FutureDay;
StartDay = (localtime(&Start)->tm_hour + 1) % 24;
FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
}
static time_t
RelativeDate(Start, DayOrdinal, DayNumber)
time_t Start;
time_t DayOrdinal;
time_t DayNumber;
{
struct tm *tm;
time_t now;
now = Start;
tm = localtime(&now);
now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
return DSTcorrect(Start, now);
}
static time_t
RelativeMonth(Start, RelMonth)
time_t Start;
time_t RelMonth;
{
struct tm *tm;
time_t Month;
time_t Year;
if (RelMonth == 0)
return 0;
tm = localtime(&Start);
Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
Year = Month / 12;
Month = Month % 12 + 1;
return DSTcorrect(Start,
Convert(Month, (time_t)tm->tm_mday, Year,
(time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
MER24, DSTmaybe));
}
static int
LookupWord(buff)
char *buff;
{
register char *p;
register char *q;
register TABLE *tp;
int i;
int abbrev;
/* Make it lowercase. */
for (p = buff; *p; p++)
if (isupper(*p))
*p = tolower(*p);
if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
yylval.Meridian = MERam;
return tMERIDIAN;
}
if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
yylval.Meridian = MERpm;
return tMERIDIAN;
}
/* See if we have an abbreviation for a month. */
if (strlen(buff) == 3)
abbrev = 1;
else if (strlen(buff) == 4 && buff[3] == '.') {
abbrev = 1;
buff[3] = '\0';
}
else
abbrev = 0;
for (tp = MonthDayTable; tp->name; tp++) {
if (abbrev) {
if (strncmp(buff, tp->name, 3) == 0) {
yylval.Number = tp->value;
return tp->type;
}
}
else if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
}
for (tp = TimezoneTable; tp->name; tp++)
if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
if (strcmp(buff, "dst") == 0)
return tDST;
for (tp = UnitsTable; tp->name; tp++)
if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
/* Strip off any plural and try the units table again. */
i = strlen(buff) - 1;
if (buff[i] == 's') {
buff[i] = '\0';
for (tp = UnitsTable; tp->name; tp++)
if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
buff[i] = 's'; /* Put back for "this" in OtherTable. */
}
for (tp = OtherTable; tp->name; tp++)
if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
/* Military timezones. */
if (buff[1] == '\0' && isalpha(*buff)) {
for (tp = MilitaryTable; tp->name; tp++)
if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
}
/* Drop out any periods and try the timezone table again. */
for (i = 0, p = q = buff; *q; q++)
if (*q != '.')
*p++ = *q;
else
i++;
*p = '\0';
if (i)
for (tp = TimezoneTable; tp->name; tp++)
if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
return tID;
}
int
yylex()
{
register char c;
register char *p;
char buff[20];
int Count;
int sign;
for ( ; ; ) {
while (isspace(*yyInput))
yyInput++;
if (isdigit(c = *yyInput) || c == '-' || c == '+') {
if (c == '-' || c == '+') {
sign = c == '-' ? -1 : 1;
if (!isdigit(*++yyInput))
/* skip the '-' sign */
continue;
}
else
sign = 0;
for (yylval.Number = 0; isdigit(c = *yyInput++); )
yylval.Number = 10 * yylval.Number + c - '0';
yyInput--;
if (sign < 0)
yylval.Number = -yylval.Number;
return sign ? tSNUMBER : tUNUMBER;
}
if (isalpha(c)) {
for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
if (p < &buff[sizeof buff - 1])
*p++ = c;
*p = '\0';
yyInput--;
return LookupWord(buff);
}
if (c != '(')
return *yyInput++;
Count = 0;
do {
c = *yyInput++;
if (c == '\0')
return c;
if (c == '(')
Count++;
else if (c == ')')
Count--;
} while (Count > 0);
}
}
time_t
get_date(p, now)
char *p;
struct timeb *now;
{
struct tm *tm;
struct timeb ftz;
time_t Start;
time_t tod;
yyInput = p;
if (now == NULL) {
now = &ftz;
#if defined(FTIME_MISSING)
(void)time(&ftz.time);
/* Set the timezone global. */
tzset();
#if defined(HAVE_TIMEZONE)
tm = localtime(&ftz.time);
ftz.timezone = tm->tm_gmtoff / 60;
#else
#if defined(timezone)
ftz.tzone = (int) timezone / 60;
#else
ftz.timezone = (int) timezone / 60;
#endif /* defined(timezone) */
#endif /* defined(HAVE_TIMEZONE) */
#else
(void)ftime(&ftz);
#endif /* defined(FTIME_MISSING) */
}
tm = localtime(&now->time);
yyYear = tm->tm_year;
yyMonth = tm->tm_mon + 1;
yyDay = tm->tm_mday;
#if defined(timezone)
yyTimezone = now->tzone;
#else
yyTimezone = now->timezone;
#endif /* defined(timezone) */
yyDSTmode = DSTmaybe;
yyHour = 0;
yyMinutes = 0;
yySeconds = 0;
yyMeridian = MER24;
yyRelSeconds = 0;
yyRelMonth = 0;
yyHaveDate = 0;
yyHaveDay = 0;
yyHaveRel = 0;
yyHaveTime = 0;
yyHaveZone = 0;
if (yyparse()
|| yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
return -1;
if (yyHaveDate || yyHaveTime || yyHaveDay) {
Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
yyMeridian, yyDSTmode);
if (Start < 0)
return -1;
}
else {
Start = now->time;
if (!yyHaveRel)
Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
}
Start += yyRelSeconds;
Start += RelativeMonth(Start, yyRelMonth);
if (yyHaveDay && !yyHaveDate) {
tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
Start += tod;
}
/* Have to do *something* with a legitimate -1 so it's distinguishable
* from the error return value. (Alternately could set errno on error.) */
return Start == -1 ? 0 : Start;
}
#if defined(TEST)
/* ARGSUSED */
main(ac, av)
int ac;
char *av[];
{
char buff[128];
time_t d;
(void)printf("Enter date, or blank line to exit.\n\t> ");
(void)fflush(stdout);
while (gets(buff) && buff[0]) {
d = get_date(buff, (struct timeb *)NULL);
if (d == -1)
(void)printf("Bad format - couldn't convert.\n");
else
(void)printf("%s", ctime(&d));
(void)printf("\t> ");
(void)fflush(stdout);
}
exit(0);
/* NOTREACHED */
}
#endif /* defined(TEST) */

View File

@ -0,0 +1,604 @@
/* Getopt for GNU.
Copyright (C) 1987-1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#if !__STDC__
#define const
#endif
/* This version of `getopt' appears to the caller like standard Unix `getopt'
but it behaves differently for the user, since it allows the user
to intersperse the options with the other arguments.
As `getopt' works, it permutes the elements of `argv' so that,
when it is done, all the options precede everything else. Thus
all application programs are extended to handle flexible argument order.
Setting the environment variable _POSIX_OPTION_ORDER disables permutation.
Then the behavior is completely standard.
GNU application programs can use a third alternative mode in which
they can distinguish the relative order of options and other arguments. */
#ifndef lint
static char rcsid[] = "@(#)getopt.c 1.7 92/03/31";
#endif
#include <stdio.h>
#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__)
#include <stdlib.h>
#else /* STDC_HEADERS or __GNU_LIBRARY__ */
char *getenv ();
char *malloc ();
#endif /* STDC_HEADERS or __GNU_LIBRARY__ */
/* AIX requires this to be the first thing in the file. */
#ifdef __GNUC__
#if !defined(bsdi) && !defined(__386BSD__)
#define alloca __builtin_alloca
#endif
#else /* not __GNUC__ */
#ifdef sparc
#include <alloca.h>
#else
#ifdef _AIX
#pragma alloca
#else
char *alloca ();
#endif
#endif /* sparc */
#endif /* not __GNUC__ */
#if defined(USG) || defined(STDC_HEADERS) || defined(__GNU_LIBRARY__)
#include <string.h>
#ifndef bcopy
#define bcopy(s, d, n) memcpy ((d), (s), (n))
#endif
#ifndef index
#define index strchr
#endif
#else /* USG or STDC_HEADERS or __GNU_LIBRARY__ */
#ifdef VMS
#include <string.h>
#else /* VMS */
#include <strings.h>
#endif /* VMS */
/* Declaring bcopy causes errors on systems whose declarations are different.
If the declaration is omitted, everything works fine. */
#endif /* USG or STDC_HEADERS or __GNU_LIBRARY__ */
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
char *optarg = 0;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
int optind = 0;
/* The next char to be scanned in the option-element
in which the last option character we returned was found.
This allows us to pick up the scan where we left off.
If this is zero, or a null string, it means resume the scan
by advancing to the next ARGV-element. */
static char *nextchar;
/* Callers store zero here to inhibit the error message
for unrecognized options. */
int opterr = 1;
/* Describe how to deal with options that follow non-option ARGV-elements.
If the caller did not specify anything,
the default is REQUIRE_ORDER if the environment variable
_POSIX_OPTION_ORDER is defined, PERMUTE otherwise.
REQUIRE_ORDER means don't recognize them as options;
stop option processing when the first non-option is seen.
This is what Unix does.
This mode of operation is selected by either setting the environment
variable POSIX_ME_HARDER, or using `+' as the first character
of the list of option characters.
PERMUTE is the default. We permute the contents of ARGV as we scan,
so that eventually all the non-options are at the end. This allows options
to be given in any order, even with programs that were not written to
expect this.
RETURN_IN_ORDER is an option available to programs that were written
to expect options and other ARGV-elements in any order and that care about
the ordering of the two. We describe each non-option ARGV-element
as if it were the argument of an option with character code 1.
Using `-' as the first character of the list of option characters
selects this mode of operation.
The special argument `--' forces an end of option-scanning regardless
of the value of `ordering'. In the case of RETURN_IN_ORDER, only
`--' can cause `getopt' to return EOF with `optind' != ARGC. */
static enum
{
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
} ordering;
/* Describe the long-named options requested by the application.
_GETOPT_LONG_OPTIONS is a vector of `struct option' terminated by an
element containing a name which is zero.
The field `has_arg' is 1 if the option takes an argument,
2 if it takes an optional argument. */
struct option
{
char *name;
int has_arg;
int *flag;
int val;
};
const struct option *_getopt_long_options;
int _getopt_long_only = 0;
/* Index in _GETOPT_LONG_OPTIONS of the long-named option actually found.
Only valid when a long-named option was found. */
int option_index;
/* Handle permutation of arguments. */
/* Describe the part of ARGV that contains non-options that have
been skipped. `first_nonopt' is the index in ARGV of the first of them;
`last_nonopt' is the index after the last of them. */
static int first_nonopt;
static int last_nonopt;
/* Exchange two adjacent subsequences of ARGV.
One subsequence is elements [first_nonopt,last_nonopt)
which contains all the non-options that have been skipped so far.
The other is elements [last_nonopt,optind), which contains all
the options processed since those non-options were skipped.
`first_nonopt' and `last_nonopt' are relocated so that they describe
the new indices of the non-options in ARGV after they are moved. */
static void
exchange (argv)
char **argv;
{
int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
char **temp = (char **) alloca (nonopts_size);
/* Interchange the two blocks of data in ARGV. */
bcopy (&argv[first_nonopt], temp, nonopts_size);
bcopy (&argv[last_nonopt], &argv[first_nonopt],
(optind - last_nonopt) * sizeof (char *));
bcopy (temp, &argv[first_nonopt + optind - last_nonopt], nonopts_size);
/* Update records for the slots the non-options now occupy. */
first_nonopt += (optind - last_nonopt);
last_nonopt = optind;
}
/* Scan elements of ARGV (whose length is ARGC) for option characters
given in OPTSTRING.
If an element of ARGV starts with '-', and is not exactly "-" or "--",
then it is an option element. The characters of this element
(aside from the initial '-') are option characters. If `getopt'
is called repeatedly, it returns successively each of the option characters
from each of the option elements.
If `getopt' finds another option character, it returns that character,
updating `optind' and `nextchar' so that the next call to `getopt' can
resume the scan with the following option character or ARGV-element.
If there are no more option characters, `getopt' returns `EOF'.
Then `optind' is the index in ARGV of the first ARGV-element
that is not an option. (The ARGV-elements have been permuted
so that those that are not options now come last.)
OPTSTRING is a string containing the legitimate option characters.
If an option character is seen that is not listed in OPTSTRING,
return '?' after printing an error message. If you set `opterr' to
zero, the error message is suppressed but we still return '?'.
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
so the following text in the same ARGV-element, or the text of the following
ARGV-element, is returned in `optarg'. Two colons mean an option that
wants an optional arg; if there is text in the current ARGV-element,
it is returned in `optarg', otherwise `optarg' is set to zero.
If OPTSTRING starts with `-' or `+', it requests different methods of
handling the non-option ARGV-elements.
See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
Long-named options begin with `+' instead of `-'.
Their names may be abbreviated as long as the abbreviation is unique
or is an exact match for some defined option. If they have an
argument, it follows the option name in the same ARGV-element, separated
from the option name by a `=', or else the in next ARGV-element.
When `getopt' finds a long-named option, it returns 0 if that option's
`flag' field is nonzero, the value of the option's `val' field
otherwise. */
int
gnu_getopt (argc, argv, optstring)
int argc;
char **argv;
const char *optstring;
{
optarg = 0;
/* Initialize the internal data when the first call is made.
Start processing options with ARGV-element 1 (since ARGV-element 0
is the program name); the sequence of previously skipped
non-option ARGV-elements is empty. */
if (optind == 0)
{
first_nonopt = last_nonopt = optind = 1;
nextchar = 0;
/* Determine how to handle the ordering of options and nonoptions. */
if (optstring[0] == '-')
{
ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == '+')
{
ordering = REQUIRE_ORDER;
++optstring;
}
else if (getenv ("POSIX_ME_HARDER") != 0)
ordering = REQUIRE_ORDER;
else
ordering = PERMUTE;
}
if (nextchar == 0 || *nextchar == 0)
{
if (ordering == PERMUTE)
{
/* If we have just processed some options following some non-options,
exchange them so that the options come first. */
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange (argv);
else if (last_nonopt != optind)
first_nonopt = optind;
/* Now skip any additional non-options
and extend the range of non-options previously skipped. */
while (optind < argc
&& (argv[optind][0] != '-'
|| argv[optind][1] == 0)
&& (_getopt_long_options == 0
|| argv[optind][0] != '+'
|| argv[optind][1] == 0))
optind++;
last_nonopt = optind;
}
/* Special ARGV-element `--' means premature end of options.
Skip it like a null option,
then exchange with previous non-options as if it were an option,
then skip everything else like a non-option. */
if (optind != argc && !strcmp (argv[optind], "--"))
{
optind++;
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange (argv);
else if (first_nonopt == last_nonopt)
first_nonopt = optind;
last_nonopt = argc;
optind = argc;
}
/* If we have done all the ARGV-elements, stop the scan
and back over any non-options that we skipped and permuted. */
if (optind == argc)
{
/* Set the next-arg-index to point at the non-options
that we previously skipped, so the caller will digest them. */
if (first_nonopt != last_nonopt)
optind = first_nonopt;
return EOF;
}
/* If we have come to a non-option and did not permute it,
either stop the scan or describe it to the caller and pass it by. */
if ((argv[optind][0] != '-' || argv[optind][1] == 0)
&& (_getopt_long_options == 0
|| argv[optind][0] != '+' || argv[optind][1] == 0))
{
if (ordering == REQUIRE_ORDER)
return EOF;
optarg = argv[optind++];
return 1;
}
/* We have found another option-ARGV-element.
Start decoding its characters. */
nextchar = argv[optind] + 1;
}
if (_getopt_long_options != 0
&& (argv[optind][0] == '+'
|| (_getopt_long_only && argv[optind][0] == '-'))
)
{
const struct option *p;
char *s = nextchar;
int exact = 0;
int ambig = 0;
const struct option *pfound = 0;
int indfound = 0;
while (*s && *s != '=')
s++;
/* Test all options for either exact match or abbreviated matches. */
for (p = _getopt_long_options, option_index = 0; p->name;
p++, option_index++)
if (!strncmp (p->name, nextchar, s - nextchar))
{
if (s - nextchar == strlen (p->name))
{
/* Exact match found. */
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == 0)
{
/* First nonexact match found. */
pfound = p;
indfound = option_index;
}
else
/* Second nonexact match found. */
ambig = 1;
}
if (ambig && !exact)
{
fprintf (stderr, "%s: option `%s' is ambiguous\n",
argv[0], argv[optind]);
nextchar += strlen (nextchar);
optind++;
return '?';
}
if (pfound != 0)
{
option_index = indfound;
optind++;
if (*s)
{
if (pfound->has_arg > 0)
optarg = s + 1;
else
{
fprintf (stderr,
"%s: option `%c%s' doesn't allow an argument\n",
argv[0], argv[optind - 1][0], pfound->name);
nextchar += strlen (nextchar);
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (optind < argc)
optarg = argv[optind++];
else
{
fprintf (stderr, "%s: option `%s' requires an argument\n",
argv[0], argv[optind - 1]);
nextchar += strlen (nextchar);
return '?';
}
}
nextchar += strlen (nextchar);
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
/* Can't find it as a long option. If this is getopt_long_only,
and the option starts with '-' and is a valid short
option, then interpret it as a short option. Otherwise it's
an error. */
if (_getopt_long_only == 0 || argv[optind][0] == '+' ||
index (optstring, *nextchar) == 0)
{
if (opterr != 0)
fprintf (stderr, "%s: unrecognized option `%c%s'\n",
argv[0], argv[optind][0], nextchar);
nextchar += strlen (nextchar);
optind++;
return '?';
}
}
/* Look at and handle the next option-character. */
{
char c = *nextchar++;
char *temp = index (optstring, c);
/* Increment `optind' when we start to process its last character. */
if (*nextchar == 0)
optind++;
if (temp == 0 || c == ':')
{
if (opterr != 0)
{
if (c < 040 || c >= 0177)
fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
argv[0], c);
else
fprintf (stderr, "%s: unrecognized option `-%c'\n",
argv[0], c);
}
return '?';
}
if (temp[1] == ':')
{
if (temp[2] == ':')
{
/* This is an option that accepts an argument optionally. */
if (*nextchar != 0)
{
optarg = nextchar;
optind++;
}
else
optarg = 0;
nextchar = 0;
}
else
{
/* This is an option that requires an argument. */
if (*nextchar != 0)
{
optarg = nextchar;
/* If we end this ARGV-element by taking the rest as an arg,
we must advance to the next element now. */
optind++;
}
else if (optind == argc)
{
if (opterr != 0)
fprintf (stderr, "%s: option `-%c' requires an argument\n",
argv[0], c);
c = '?';
}
else
/* We already incremented `optind' once;
increment it again when taking next ARGV-elt as argument. */
optarg = argv[optind++];
nextchar = 0;
}
}
return c;
}
}
#ifdef TEST
/* Compile with -DTEST to make an executable for use in testing
the above definition of `getopt'. */
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
c = gnu_getopt (argc, argv, "abc:d:0123456789");
if (c == EOF)
break;
switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */

View File

@ -0,0 +1,102 @@
/* declarations for getopt
Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* @(#)getopt.h 1.6 92/03/31 */
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int optind;
/* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int opterr;
/* Describe the long-named options requested by the application.
_GETOPT_LONG_OPTIONS is a vector of `struct option' terminated by an
element containing a name which is zero.
The field `has_arg' is:
0 if the option does not take an argument,
1 if the option requires an argument,
2 if the option takes an optional argument.
If the field `flag' is nonzero, it points to a variable that is set
to the value given in the field `val' when the option is found, but
left unchanged if the option is not found.
To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
struct option
{
char *name;
int has_arg;
int *flag;
int val;
};
#if __STDC__
extern const struct option *_getopt_long_options;
#else
extern struct option *_getopt_long_options;
#endif
/* If nonzero, '-' can introduce long-named options.
Set by getopt_long_only. */
extern int _getopt_long_only;
/* The index in GETOPT_LONG_OPTIONS of the long-named option found.
Only valid when a long-named option has been found by the most
recent call to `getopt'. */
extern int option_index;
#if __STDC__
int gnu_getopt (int argc, char **argv, const char *shortopts);
int gnu_getopt_long (int argc, char **argv, const char *shortopts,
const struct option *longopts, int *longind);
int gnu_getopt_long_only (int argc, char **argv, const char *shortopts,
const struct option *longopts, int *longind);
#else
int gnu_getopt ();
int gnu_getopt_long ();
int gnu_getopt_long_only ();
#endif

View File

@ -0,0 +1,166 @@
/* Getopt for GNU.
Copyright (C) 1987-1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "getopt.h"
#if !__STDC__
#define const
#endif
#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__)
#include <stdlib.h>
#else /* STDC_HEADERS or __GNU_LIBRARY__ */
char *getenv ();
#endif /* STDC_HEADERS or __GNU_LIBRARY__ */
#if !defined (NULL)
#define NULL 0
#endif
int
gnu_getopt_long (argc, argv, options, long_options, opt_index)
int argc;
char **argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
int val;
/* For strict POSIX compatibility, we must turn off long options. */
if (getenv ("POSIX_ME_HARDER") == 0)
_getopt_long_options = long_options;
val = gnu_getopt (argc, argv, options);
if (val == 0 && opt_index != NULL)
*opt_index = option_index;
return val;
}
/* Like getopt_long, but '-' as well as '+' can indicate a long option.
If an option that starts with '-' doesn't match a long option,
but does match a short option, it is parsed as a short option
instead. */
int
gnu_getopt_long_only (argc, argv, options, long_options, opt_index)
int argc;
char **argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
int val;
_getopt_long_options = long_options;
_getopt_long_only = 1;
val = gnu_getopt (argc, argv, options);
if (val == 0 && opt_index != NULL)
*opt_index = option_index;
return val;
}
#ifdef TEST
#include <stdio.h>
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
char *name = '\0';
int option_index = 0;
static struct option long_options[] =
{
{"add", 1, 0, 0},
{"append", 0, 0, 0},
{"delete", 1, 0, 0},
{"verbose", 0, 0, 0},
{"create", 0, 0, 0},
{"file", 1, 0, 0},
{0, 0, 0, 0}
};
c = getopt_long (argc, argv, "abc:d:0123456789",
long_options, &option_index);
if (c == EOF)
break;
switch (c)
{
case 0:
printf ("option %s", (long_options[option_index]).name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */

View File

@ -0,0 +1,31 @@
/* getwd.c -- get current working directory pathname
Copyright (C) 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Some systems which include both getwd() and getcwd() have an implementation
of getwd() which is much faster than getcwd(). As a result, we use the
system's getwd() if it is available */
#include "system.h"
/* Get the current working directory into PATHNAME */
char *
getwd (pathname)
char *pathname;
{
return (getcwd(pathname, PATH_MAX));
}

338
gnu/usr.bin/cvs/lib/hash.c Normal file
View File

@ -0,0 +1,338 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* Polk's hash list manager. So cool.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)hash.c 1.14 92/03/31";
#endif
/* global caches */
static List *listcache = NULL;
static Node *nodecache = NULL;
#if __STDC__
static void freenode_mem (Node * p);
#else
static void freenode_mem ();
#endif /* __STDC__ */
/* hash function */
static int
hashp (key)
char *key;
{
register char *p;
register int n = 0;
for (p = key; *p; p++)
n += *p;
return (n % HASHSIZE);
}
/*
* create a new list (or get an old one from the cache)
*/
List *
getlist ()
{
int i;
List *list;
Node *node;
if (listcache != NULL)
{
/* get a list from the cache and clear it */
list = listcache;
listcache = listcache->next;
list->next = (List *) NULL;
for (i = 0; i < HASHSIZE; i++)
list->hasharray[i] = (Node *) NULL;
}
else
{
/* make a new list from scratch */
list = (List *) xmalloc (sizeof (List));
bzero ((char *) list, sizeof (List));
node = getnode ();
list->list = node;
node->type = HEADER;
node->next = node->prev = node;
}
return (list);
}
/*
* free up a list
*/
void
dellist (listp)
List **listp;
{
int i;
Node *p;
if (*listp == (List *) NULL)
return;
p = (*listp)->list;
/* free each node in the list (except header) */
while (p->next != p)
delnode (p->next);
/* free any list-private data, without freeing the actual header */
freenode_mem (p);
/* free up the header nodes for hash lists (if any) */
for (i = 0; i < HASHSIZE; i++)
{
if ((p = (*listp)->hasharray[i]) != (Node *) NULL)
{
/* put the nodes into the cache */
p->type = UNKNOWN;
p->next = nodecache;
nodecache = p;
}
}
/* put it on the cache */
(*listp)->next = listcache;
listcache = *listp;
*listp = (List *) NULL;
}
/*
* get a new list node
*/
Node *
getnode ()
{
Node *p;
if (nodecache != (Node *) NULL)
{
/* get one from the cache */
p = nodecache;
nodecache = p->next;
}
else
{
/* make a new one */
p = (Node *) xmalloc (sizeof (Node));
}
/* always make it clean */
bzero ((char *) p, sizeof (Node));
p->type = UNKNOWN;
return (p);
}
/*
* remove a node from it's list (maybe hash list too) and free it
*/
void
delnode (p)
Node *p;
{
if (p == (Node *) NULL)
return;
/* take it out of the list */
p->next->prev = p->prev;
p->prev->next = p->next;
/* if it was hashed, remove it from there too */
if (p->hashnext != (Node *) NULL)
{
p->hashnext->hashprev = p->hashprev;
p->hashprev->hashnext = p->hashnext;
}
/* free up the storage */
freenode (p);
}
/*
* free up the storage associated with a node
*/
static void
freenode_mem (p)
Node *p;
{
if (p->delproc != (void (*) ()) NULL)
p->delproc (p); /* call the specified delproc */
else
{
if (p->data != NULL) /* otherwise free() it if necessary */
free (p->data);
}
if (p->key != NULL) /* free the key if necessary */
free (p->key);
/* to be safe, re-initialize these */
p->key = p->data = (char *) NULL;
p->delproc = (void (*) ()) NULL;
}
/*
* free up the storage associated with a node and recycle it
*/
void
freenode (p)
Node *p;
{
/* first free the memory */
freenode_mem (p);
/* then put it in the cache */
p->type = UNKNOWN;
p->next = nodecache;
nodecache = p;
}
/*
* insert item p at end of list "list" (maybe hash it too) if hashing and it
* already exists, return -1 and don't actually put it in the list
*
* return 0 on success
*/
int
addnode (list, p)
List *list;
Node *p;
{
int hashval;
Node *q;
if (p->key != NULL) /* hash it too? */
{
hashval = hashp (p->key);
if (list->hasharray[hashval] == NULL) /* make a header for list? */
{
q = getnode ();
q->type = HEADER;
list->hasharray[hashval] = q->hashnext = q->hashprev = q;
}
/* put it into the hash list if it's not already there */
for (q = list->hasharray[hashval]->hashnext;
q != list->hasharray[hashval]; q = q->hashnext)
{
if (strcmp (p->key, q->key) == 0)
return (-1);
}
q = list->hasharray[hashval];
p->hashprev = q->hashprev;
p->hashnext = q;
p->hashprev->hashnext = p;
q->hashprev = p;
}
/* put it into the regular list */
p->prev = list->list->prev;
p->next = list->list;
list->list->prev->next = p;
list->list->prev = p;
return (0);
}
/*
* look up an entry in hash list table
*/
Node *
findnode (list, key)
List *list;
char *key;
{
Node *head, *p;
if (list == (List *) NULL)
return ((Node *) NULL);
head = list->hasharray[hashp (key)];
if (head == (Node *) NULL)
return ((Node *) NULL);
for (p = head->hashnext; p != head; p = p->hashnext)
if (strcmp (p->key, key) == 0)
return (p);
return ((Node *) NULL);
}
/*
* walk a list with a specific proc
*/
int
walklist (list, proc)
List *list;
int (*proc) ();
{
Node *head, *p;
int err = 0;
if (list == NULL)
return (0);
head = list->list;
for (p = head->next; p != head; p = p->next)
err += proc (p);
return (err);
}
/*
* sort the elements of a list (in place)
*/
void
sortlist (list, comp)
List *list;
int (*comp) ();
{
Node *head, *remain, *p, *q;
/* save the old first element of the list */
head = list->list;
remain = head->next;
/* make the header node into a null list of it's own */
head->next = head->prev = head;
/* while there are nodes remaining, do insert sort */
while (remain != head)
{
/* take one from the list */
p = remain;
remain = remain->next;
/* traverse the sorted list looking for the place to insert it */
for (q = head->next; q != head; q = q->next)
{
if (comp (p, q) < 0)
{
/* p comes before q */
p->next = q;
p->prev = q->prev;
p->prev->next = p;
q->prev = p;
break;
}
}
if (q == head)
{
/* it belongs at the end of the list */
p->next = head;
p->prev = head->prev;
p->prev->next = p;
head->prev = p;
}
}
}

View File

@ -0,0 +1,77 @@
/* @(#)hash.h 1.18 92/03/31 */
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*/
/*
* The number of buckets for the hash table contained in each list. This
* should probably be prime.
*/
#define HASHSIZE 151
/*
* Types of nodes
*/
enum ntype
{
UNKNOWN, HEADER, ENTRIES, FILES, LIST, RCSNODE,
RCSVERS, DIRS, UPDATE, LOCK, NDBMNODE
};
typedef enum ntype Ntype;
struct node
{
Ntype type;
struct node *next;
struct node *prev;
struct node *hashnext;
struct node *hashprev;
char *key;
char *data;
void (*delproc) ();
};
typedef struct node Node;
struct list
{
Node *list;
Node *hasharray[HASHSIZE];
struct list *next;
};
typedef struct list List;
struct entnode
{
char *version;
char *timestamp;
char *options;
char *tag;
char *date;
};
typedef struct entnode Entnode;
#if __STDC__
List *getlist (void);
Node *findnode (List * list, char *key);
Node *getnode (void);
int addnode (List * list, Node * p);
int walklist (List * list, int (*proc) ());
void dellist (List ** listp);
void delnode (Node * p);
void freenode (Node * p);
void sortlist (List * list, int (*comp) ());
#else
List *getlist ();
Node *findnode ();
Node *getnode ();
int addnode ();
int walklist ();
void dellist ();
void delnode ();
void freenode ();
void sortlist ();
#endif /* __STDC__ */

125
gnu/usr.bin/cvs/lib/mkdir.c Normal file
View File

@ -0,0 +1,125 @@
/* mkrmdir.c -- BSD compatible directory functions for System V
Copyright (C) 1988, 1990 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#ifndef STDC_HEADERS
extern int errno;
#endif
/* mkdir and rmdir adapted from GNU tar. */
/* Make directory DPATH, with permission mode DMODE.
Written by Robert Rother, Mariah Corporation, August 1985
(sdcsvax!rmr or rmr@uscd). If you want it, it's yours.
Severely hacked over by John Gilmore to make a 4.2BSD compatible
subroutine. 11Mar86; hoptoad!gnu
Modified by rmtodd@uokmax 6-28-87 -- when making an already existing dir,
subroutine didn't return EEXIST. It does now. */
int
mkdir (dpath, dmode)
char *dpath;
int dmode;
{
int cpid, status;
struct stat statbuf;
if (stat (dpath, &statbuf) == 0)
{
errno = EEXIST; /* stat worked, so it already exists. */
return -1;
}
/* If stat fails for a reason other than non-existence, return error. */
if (errno != ENOENT)
return -1;
cpid = fork ();
switch (cpid)
{
case -1: /* Cannot fork. */
return -1; /* errno is set already. */
case 0: /* Child process. */
/* Cheap hack to set mode of new directory. Since this child
process is going away anyway, we zap its umask.
This won't suffice to set SUID, SGID, etc. on this
directory, so the parent process calls chmod afterward. */
status = umask (0); /* Get current umask. */
umask (status | (0777 & ~dmode)); /* Set for mkdir. */
execl ("/bin/mkdir", "mkdir", dpath, (char *) 0);
_exit (1);
default: /* Parent process. */
while (wait (&status) != cpid) /* Wait for kid to finish. */
/* Do nothing. */ ;
if (status & 0xFFFF)
{
errno = EIO; /* /bin/mkdir failed. */
return -1;
}
return chmod (dpath, dmode);
}
}
/* Remove directory DPATH.
Return 0 if successful, -1 if not. */
int
rmdir (dpath)
char *dpath;
{
int cpid, status;
struct stat statbuf;
if (stat (dpath, &statbuf) != 0)
return -1; /* stat set errno. */
if ((statbuf.st_mode & S_IFMT) != S_IFDIR)
{
errno = ENOTDIR;
return -1;
}
cpid = fork ();
switch (cpid)
{
case -1: /* Cannot fork. */
return -1; /* errno is set already. */
case 0: /* Child process. */
execl ("/bin/rmdir", "rmdir", dpath, (char *) 0);
_exit (1);
default: /* Parent process. */
while (wait (&status) != cpid) /* Wait for kid to finish. */
/* Do nothing. */ ;
if (status & 0xFFFF)
{
errno = EIO; /* /bin/rmdir failed. */
return -1;
}
return 0;
}
}

View File

@ -0,0 +1,212 @@
/*
* Copyright (c) 1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* A simple ndbm-emulator for CVS. It parses a text file of the format:
*
* key value
*
* at dbm_open time, and loads the entire file into memory. As such, it is
* probably only good for fairly small modules files. Ours is about 30K in
* size, and this code works fine.
*/
#include "cvs.h"
#ifdef MY_NDBM
#ifndef lint
static char rcsid[] = "@(#)myndbm.c 1.5 92/03/31";
#endif
static void mydbm_load_file ();
/* ARGSUSED */
DBM *
mydbm_open (file, flags, mode)
char *file;
int flags;
int mode;
{
FILE *fp;
DBM *db;
if ((fp = fopen (file, "r")) == NULL)
return ((DBM *) 0);
db = (DBM *) xmalloc (sizeof (*db));
db->dbm_list = getlist ();
mydbm_load_file (fp, db->dbm_list);
(void) fclose (fp);
return (db);
}
void
mydbm_close (db)
DBM *db;
{
dellist (&db->dbm_list);
free ((char *) db);
}
datum
mydbm_fetch (db, key)
DBM *db;
datum key;
{
Node *p;
char *s;
datum val;
/* make sure it's null-terminated */
s = xmalloc (key.dsize + 1);
(void) strncpy (s, key.dptr, key.dsize);
s[key.dsize] = '\0';
p = findnode (db->dbm_list, s);
if (p)
{
val.dptr = p->data;
val.dsize = strlen (p->data);
}
else
{
val.dptr = (char *) NULL;
val.dsize = 0;
}
free (s);
return (val);
}
datum
mydbm_firstkey (db)
DBM *db;
{
Node *head, *p;
datum key;
head = db->dbm_list->list;
p = head->next;
if (p != head)
{
key.dptr = p->key;
key.dsize = strlen (p->key);
}
else
{
key.dptr = (char *) NULL;
key.dsize = 0;
}
db->dbm_next = p->next;
return (key);
}
datum
mydbm_nextkey (db)
DBM *db;
{
Node *head, *p;
datum key;
head = db->dbm_list->list;
p = db->dbm_next;
if (p != head)
{
key.dptr = p->key;
key.dsize = strlen (p->key);
}
else
{
key.dptr = (char *) NULL;
key.dsize = 0;
}
db->dbm_next = p->next;
return (key);
}
static void
mydbm_load_file (fp, list)
FILE *fp;
List *list;
{
char line[MAXLINELEN], value[MAXLINELEN];
char *cp, *vp;
int len, cont;
for (cont = 0; fgets (line, sizeof (line), fp) != NULL;)
{
if ((cp = rindex (line, '\n')) != NULL)
*cp = '\0'; /* strip the newline */
/*
* Add the line to the value, at the end if this is a continuation
* line; otherwise at the beginning, but only after any trailing
* backslash is removed.
*/
vp = value;
if (cont)
vp += strlen (value);
/*
* See if the line we read is a continuation line, and strip the
* backslash if so.
*/
len = strlen (line);
if (len > 0)
cp = &line[len - 1];
else
cp = line;
if (*cp == '\\')
{
cont = 1;
*cp = '\0';
}
else
{
cont = 0;
}
(void) strcpy (vp, line);
if (value[0] == '#')
continue; /* comment line */
vp = value;
while (*vp && isspace (*vp))
vp++;
if (*vp == '\0')
continue; /* empty line */
/*
* If this was not a continuation line, add the entry to the database
*/
if (!cont)
{
Node *p = getnode ();
char *kp;
kp = vp;
while (*vp && !isspace (*vp))
vp++;
*vp++ = '\0'; /* NULL terminate the key */
p->type = NDBMNODE;
p->key = xstrdup (kp);
while (*vp && isspace (*vp))
vp++; /* skip whitespace to value */
if (*vp == '\0')
{
error (0, 0, "warning: NULL value for key `%s'", p->key);
freenode (p);
continue;
}
p->data = xstrdup (vp);
if (addnode (list, p) == -1)
{
error (0, 0, "duplicate key found for `%s'", p->key);
freenode (p);
}
}
}
}
#endif /* MY_NDBM */

View File

@ -0,0 +1,44 @@
/* @(#)myndbm.h 1.3 92/02/29 */
#ifdef MY_NDBM
#define DBLKSIZ 4096
typedef struct
{
List *dbm_list; /* cached database */
Node *dbm_next; /* next key to return for nextkey() */
} DBM;
typedef struct
{
char *dptr;
int dsize;
} datum;
/*
* So as not to conflict with other dbm_open, etc., routines that may
* be included by someone's libc, all of my emulation routines are prefixed
* by "my" and we define the "standard" ones to be "my" ones here.
*/
#define dbm_open mydbm_open
#define dbm_close mydbm_close
#define dbm_fetch mydbm_fetch
#define dbm_firstkey mydbm_firstkey
#define dbm_nextkey mydbm_nextkey
#if __STDC__
DBM *mydbm_open (char *file, int flags, int mode);
void mydbm_close (DBM * db);
datum mydbm_fetch (DBM * db, datum key);
datum mydbm_firstkey (DBM * db);
datum mydbm_nextkey (DBM * db);
#else
DBM *mydbm_open ();
void mydbm_close ();
datum mydbm_fetch ();
datum mydbm_firstkey ();
datum mydbm_nextkey ();
#endif /* __STDC__ */
#endif /* MY_NDBM */

4867
gnu/usr.bin/cvs/lib/regex.c Normal file

File diff suppressed because it is too large Load Diff

479
gnu/usr.bin/cvs/lib/regex.h Normal file
View File

@ -0,0 +1,479 @@
/* Definitions for data structures and routines for the regular
expression library, version REPLACE-WITH-VERSION.
Copyright (C) 1985, 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef __REGEXP_LIBRARY_H__
#define __REGEXP_LIBRARY_H__
/* POSIX says that <sys/types.h> must be included before <regex.h>. */
/* The following bits are used to determine the regexp syntax we
recognize. The set/not-set meanings are chosen so that Emacs syntax
remains the value 0. The bits are given in alphabetical order, and
the definitions shifted by one from the previous bit; thus, when we
add or remove a bit, only one other definition need change. */
typedef unsigned reg_syntax_t;
/* If this bit is not set, then \ inside a bracket expression is literal.
If set, then such a \ quotes the following character. */
#define RE_BACKSLASH_ESCAPE_IN_LISTS (1)
/* If this bit is not set, then + and ? are operators, and \+ and \? are
literals.
If set, then \+ and \? are operators and + and ? are literals. */
#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
/* If this bit is set, then character classes are supported. They are:
[:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
[:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
If not set, then character classes are not supported. */
#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
/* If this bit is set, then ^ and $ are always anchors (outside bracket
expressions).
If this bit is not set, then it depends:
^ is an anchor if it is at the beginning of a regular
expression or after an open-group or an alternation operator;
$ is an anchor if it is at the end of a regular expression, or
before a close-group or an alternation operator.
This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
POSIX now says that the behavior of * etc. in leading positions is
undefined. We have already implemented a previous draft which
made those constructs invalid, so we may as well not change the code
back. */
#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
/* If this bit is set, then special characters are always special
regardless of where they are in the pattern.
If this bit is not set, then special characters are special only in
some contexts; otherwise they are ordinary. Specifically,
* + ? and intervals are only special when not after the beginning,
open-group, or alternation operator. */
#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
/* If this bit is set, then *, +, ?, and { cannot be first in an re or
immediately after an alternation or begin-group operator.
Furthermore, alternation cannot be first or last in an re, or
immediately follow another alternation or begin-group. */
#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
/* If this bit is set, then . matches a newline.
If not set, then it doesn't. */
#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
/* If this bit is set, then period doesn't match a null.
If not set, then it does. */
#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
/* If this bit is set, nonmatching lists [^...] do not match newline.
If not set, they do. */
#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
/* If this bit is set, either \{...\} or {...} defines an
interval, depending on RE_NO_BK_BRACES.
If not set, \{, \}, {, and } are literals. */
#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
/* If this bit is set, +, ? and | aren't recognized as operators.
If not set, they are. */
#define RE_LIMITED_OPS (RE_INTERVALS << 1)
/* If this bit is set, newline is an alternation operator.
If not set, newline is literal. */
#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
/* If this bit is set, newline in the pattern is an ordinary character.
If not set, newline before ^ or after $ allows the ^ or $ to be an
anchor. */
#define RE_NEWLINE_ORDINARY (RE_NEWLINE_ALT << 1)
/* If this bit is not set, then \{ and \} defines an interval,
and { and } are literals.
If set, then { and } defines an interval, and \{ and \} are literals. */
#define RE_NO_BK_BRACES (RE_NEWLINE_ORDINARY << 1)
/* If this bit is set, (...) defines a group, and \( and \) are literals.
If not set, \(...\) defines a group, and ( and ) are literals. */
#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
/* If this bit is set, then back references (i.e., \<digit>) are not
recognized.
If not set, then they are. */
#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
/* If this bit is set, then | is an alternation operator, and \| is literal.
If not set, then \| is an alternation operator, and | is literal. */
#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
/* If this bit is set, then you can't have empty alternatives.
If not set, then you can. */
#define RE_NO_EMPTY_ALTS (RE_NO_BK_VBAR << 1)
/* If this bit is set, then you can't have empty groups.
If not set, then you can. */
#define RE_NO_EMPTY_GROUPS (RE_NO_EMPTY_ALTS << 1)
/* If this bit is set, then an ending range point has to collate higher
than or equal to the starting range point.
If not set, then when the ending range point collates higher than the
starting range point, we consider such a range to be empty. */
#define RE_NO_EMPTY_RANGES (RE_NO_EMPTY_GROUPS << 1)
/* If this bit is set, then all back references must refer to a preceding
subexpression.
If not set, then a back reference to a nonexistent subexpression is
treated as literal characters. */
#define RE_NO_MISSING_BK_REF (RE_NO_EMPTY_RANGES << 1)
/* If this bit is set, then Regex considers an unmatched close-group
operator to be the ordinary character parenthesis.
If not set, then an unmatched close-group operator is invalid. */
#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_MISSING_BK_REF << 1)
/* This global variable defines the particular regexp syntax to use (for
some interfaces). When a regexp is compiled, the syntax used is
stored in the pattern buffer, so changing this does not affect
already-compiled regexps. */
extern reg_syntax_t obscure_syntax;
/* Define combinations of the above bits for the standard possibilities.
(The [[[ comments delimit what gets put into the Texinfo file.) */
/* [[[begin syntaxes]]] */
#define RE_SYNTAX_EMACS 0
#define RE_SYNTAX_POSIX_AWK \
(RE_CONTEXT_INDEP_ANCHORS | RE_CONTEXT_INDEP_OPS | RE_NO_BK_PARENS \
| RE_NO_BK_VBAR)
#define RE_SYNTAX_AWK \
(RE_BACKSLASH_ESCAPE_IN_LISTS | RE_SYNTAX_POSIX_AWK)
#define RE_SYNTAX_GREP \
(RE_BK_PLUS_QM | RE_NEWLINE_ALT)
#define RE_SYNTAX_EGREP \
(RE_CONTEXT_INDEP_ANCHORS | RE_CONTEXT_INDEP_OPS \
| RE_NEWLINE_ALT | RE_NO_BK_PARENS | RE_NO_BK_VBAR)
#define RE_SYNTAX_POSIX_BASIC \
(RE_CHAR_CLASSES | RE_DOT_NEWLINE \
| RE_DOT_NOT_NULL | RE_INTERVALS | RE_LIMITED_OPS \
| RE_NEWLINE_ORDINARY | RE_NO_EMPTY_RANGES | RE_NO_MISSING_BK_REF)
#define RE_SYNTAX_POSIX_EXTENDED \
(RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
| RE_CONTEXT_INVALID_OPS | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
| RE_INTERVALS | RE_NEWLINE_ORDINARY | RE_NO_BK_BRACES \
| RE_NO_BK_PARENS | RE_NO_BK_REFS | RE_NO_BK_VBAR \
| RE_NO_EMPTY_ALTS | RE_NO_EMPTY_GROUPS | RE_NO_EMPTY_RANGES \
| RE_UNMATCHED_RIGHT_PAREN_ORD)
/* [[[end syntaxes]]] */
/* Maximum number of duplicates an interval can allow. */
#undef RE_DUP_MAX
#define RE_DUP_MAX ((1 << 15) - 1)
/* POSIX `cflags' bits (i.e., information for regcomp). */
/* If this bit is set, then use extended regular expression syntax.
If not set, then use basic regular expression syntax. */
#define REG_EXTENDED 1
/* If this bit is set, then ignore case when matching.
If not set, then case is significant. */
#define REG_ICASE (REG_EXTENDED << 1)
/* If this bit is set, then anchors do not match at newline
characters in the string.
If not set, then anchors do match at newlines. */
#define REG_NEWLINE (REG_ICASE << 1)
/* If this bit is set, then report only success or fail in regexec.
If not set, then returns differ between not matching and errors. */
#define REG_NOSUB (REG_NEWLINE << 1)
/* POSIX `eflags' bits (i.e., information for regexec). */
/* If this bit is set, then the beginning-of-line operator doesn't match
the beginning of the string (presumably because it's not the
beginning of a line).
If not set, then the beginning-of-line operator does match the
beginning of the string. */
#define REG_NOTBOL 1
/* Like REG_NOTBOL, except for the end-of-line. */
#define REG_NOTEOL (1 << 1)
/* If any error codes are removed, changed, or added, update the
`re_error_msg' table in regex.c. */
typedef enum
{
REG_NOERROR = 0, /* Success. */
REG_NOMATCH, /* Didn't find a match (for regexec). */
/* POSIX regcomp return error codes. (In the order listed in the
standard.) */
REG_BADPAT, /* Invalid pattern. */
REG_ECOLLATE, /* Not implemented. */
REG_ECTYPE, /* Invalid character class name. */
REG_EESCAPE, /* Trailing backslash. */
REG_ESUBREG, /* Invalid back reference. */
REG_EBRACK, /* Unmatched left bracket. */
REG_EPAREN, /* Parenthesis imbalance. */
REG_EBRACE, /* Unmatched \{. */
REG_BADBR, /* Invalid contents of \{\}. */
REG_ERANGE, /* Invalid range end. */
REG_ESPACE, /* Ran out of memory. */
REG_BADRPT, /* No preceding re for repetition op. */
/* Error codes we've added. */
REG_EEND, /* Premature end. */
REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
} reg_errcode_t;
/* This data structure represents a compiled pattern. Before calling
the pattern compiler, the fields `buffer', `allocated', `fastmap',
`translate', and `no_sub' can be set. After the pattern has been
compiled, the `re_nsub' field is available. All other fields are
private to the regex routines. */
struct re_pattern_buffer
{
/* [[[begin pattern_buffer]]] */
/* Space that holds the compiled pattern. It is declared as
`unsigned char *' because its elements are
sometimes used as array indexes. */
unsigned char *buffer;
/* Number of bytes to which `buffer' points. */
unsigned long allocated;
/* Number of bytes actually used in `buffer'. */
unsigned long used;
/* Syntax setting with which the pattern was compiled. */
reg_syntax_t syntax;
/* Pointer to a fastmap, if any, otherwise zero. re_search uses
the fastmap, if there is one, to skip over impossible
starting points for matches. */
char *fastmap;
/* Either a translate table to apply to all characters before
comparing them, or zero for no translation. The translation
is applied to a pattern when it is compiled and to a string
when it is matched. */
char *translate;
/* Number of subexpressions found by the compiler. */
size_t re_nsub;
/* Set to 1 by re_compile_fastmap if this pattern can match the
null string; 0 prevents the searcher from matching it with
the null string. Set to 2 if it might match the null string
either at the end of a search range or just before a
character listed in the fastmap. */
unsigned can_be_null : 2;
/* Set to zero when regex_compile compiles a pattern; set to one
by re_compile_fastmap when it updates the fastmap, if any. */
unsigned fastmap_accurate : 1;
/* If set, regexec reports only success or failure and does not
return anything in pmatch. */
unsigned no_sub : 1;
/* If set, a beginning-of-line anchor doesn't match at the
beginning of the string. */
unsigned not_bol : 1;
/* Similarly for an end-of-line anchor. */
unsigned not_eol : 1;
/* If true, an anchor at a newline matches. */
unsigned newline_anchor : 1;
/* If set, re_match_2 assumes a non-null REGS argument is
initialized. If not set, REGS is initialized to the max of
RE_NREGS and re_nsub + 1 registers. */
unsigned caller_allocated_regs : 1;
/* [[[end pattern_buffer]]] */
};
typedef struct re_pattern_buffer regex_t;
/* search.c (search_buffer) in Emacs needs this one opcode value. It is
defined both in `regex.c' and here. */
#define RE_EXACTN_VALUE 1
/* Type for byte offsets within the string. POSIX mandates us defining
this. */
typedef int regoff_t;
/* This is the structure we store register match data in. See
regex.texinfo for a full description of what registers match. */
struct re_registers
{
unsigned num_regs;
regoff_t *start;
regoff_t *end;
};
/* If `caller_allocated_regs' is zero in the pattern buffer, re_match_2
returns information about this many registers. */
#ifndef RE_NREGS
#define RE_NREGS 30
#endif
/* POSIX specification for registers. Aside from the different names than
`re_registers', POSIX uses an array of structures, instead of a
structure of arrays. */
typedef struct
{
regoff_t rm_so; /* Byte offset from string's start to substring's start. */
regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
} regmatch_t;
/* Declarations for routines. */
#if __STDC__
/* Sets the current syntax to SYNTAX. You can also simply assign to the
`obscure_syntax' variable. */
extern reg_syntax_t re_set_syntax (reg_syntax_t syntax);
/* Compile the regular expression PATTERN, with length LENGTH
and syntax given by the global `obscure_syntax', into the buffer
BUFFER. Return NULL if successful, and an error string if not. */
extern const char *re_compile_pattern (const char *pattern, int length,
struct re_pattern_buffer *buffer);
/* Compile a fastmap for the compiled pattern in BUFFER; used to
accelerate searches. Return 0 if successful and -2 if was an
internal error. */
extern int re_compile_fastmap (struct re_pattern_buffer *buffer);
/* Search in the string STRING (with length LENGTH) for the pattern
compiled into BUFFER. Start searching at position START, for RANGE
characters. Return the starting position of the match, -1 for no
match, or -2 for an internal error. Also return register
information in REGS (if REGS and BUFFER->no_sub are nonzero). */
extern int re_search (struct re_pattern_buffer *buffer,
const char *string, int length,
int start, int range,
struct re_registers *regs);
/* Like `re_search', but search in the concatenation of STRING1 and
STRING2. Also, stop searching at index START + STOP. */
extern int re_search_2 (struct re_pattern_buffer *buffer,
const char *string1, int length1,
const char *string2, int length2,
int start, int range,
struct re_registers *regs,
int stop);
/* Like `re_search', but return how many characters in STRING the regexp
in BUFFER matched, starting at position START. */
extern int re_match (const struct re_pattern_buffer *buffer,
const char *string, int length,
int start, struct re_registers *regs);
/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
extern int re_match_2 (const struct re_pattern_buffer *buffer,
const char *string1, int length1,
const char *string2, int length2,
int start,
struct re_registers *regs,
int stop);
#ifndef __386BSD__
/* 4.2 bsd compatibility. */
#ifndef bsdi
extern const char *re_comp (const char *);
#endif
extern int re_exec (const char *);
#endif
/* POSIX compatibility. */
extern int regcomp (regex_t *preg, const char *pattern, int cflags);
extern int regexec (const regex_t *preg, const char *string, size_t nmatch,
regmatch_t pmatch[], int eflags);
extern size_t regerror (int errcode, const regex_t *preg, char *errbuf,
size_t errbuf_size);
extern void regfree (regex_t *preg);
#else /* not __STDC__ */
/* Support old C compilers. */
#define const
extern reg_syntax_t re_set_syntax ();
extern char *re_compile_pattern ();
extern int re_search (), re_search_2 ();
extern int re_match (), re_match_2 ();
/* 4.2 BSD compatibility. */
extern char *re_comp ();
extern int re_exec ();
/* POSIX compatibility. */
extern int regcomp ();
extern int regexec ();
extern size_t regerror ();
extern void regfree ();
#endif /* not __STDC__ */
#endif /* not __REGEXP_LIBRARY_H__ */
/*
Local variables:
make-backup-files: t
version-control: t
trim-versions-without-asking: nil
End:
*/

View File

@ -0,0 +1,68 @@
/* rename.c -- BSD compatible directory function for System V
Copyright (C) 1988, 1990 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#ifndef STDC_HEADERS
extern int errno;
#endif
/* Rename file FROM to file TO.
Return 0 if successful, -1 if not. */
int
rename (from, to)
char *from;
char *to;
{
struct stat from_stats;
int pid, status;
if (stat (from, &from_stats) == 0)
{
if (unlink (to) && errno != ENOENT)
return -1;
if ((from_stats.st_mode & S_IFMT) == S_IFDIR)
{
/* Need a setuid root process to link and unlink directories. */
pid = fork ();
switch (pid)
{
case -1: /* Error. */
error (1, errno, "cannot fork");
case 0: /* Child. */
execl (MVDIR, "mvdir", from, to, (char *) 0);
error (255, errno, "cannot run `%s'", MVDIR);
default: /* Parent. */
while (wait (&status) != pid)
/* Do nothing. */ ;
errno = 0; /* mvdir printed the system error message. */
return status != 0 ? -1 : 0;
}
}
else
{
if (link (from, to) == 0 && (unlink (from) == 0 || errno == ENOENT))
return 0;
}
}
return -1;
}

View File

@ -0,0 +1,412 @@
/* sighandle.c -- Library routines for manipulating chains of signal handlers
Copyright (C) 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Paul Sander, HaL Computer Systems, Inc. <paul@hal.com>
Brian Berliner <berliner@Sun.COM> added POSIX support */
/*************************************************************************
*
* signal.c -- This file contains code that manipulates chains of signal
* handlers.
*
* Facilities are provided to register a signal handler for
* any specific signal. When a signal is received, all of the
* registered signal handlers are invoked in the reverse order
* in which they are registered. Note that the signal handlers
* must not themselves make calls to the signal handling
* facilities.
*
* @(#)sighandle.c 1.9 92/03/31
*
*************************************************************************/
#include <sys/types.h>
#include <stdio.h>
#include <signal.h>
#ifdef STDC_HEADERS
#include <stdlib.h>
#else
#if __STDC__
char *calloc(unsigned nelem, unsigned size);
char *malloc(unsigned size);
#else
char *calloc();
char *malloc();
#endif /* __STDC__ */
#endif /* STDC_HEADERS */
#ifdef _MINIX
#undef POSIX /* Minix 1.6 doesn't support POSIX.1 sigaction yet */
#endif
#ifndef SIGTYPE
#define SIGTYPE void
#endif
/* Define the highest signal number (usually) */
#ifndef SIGMAX
#define SIGMAX 32
#endif
/* Define linked list of signal handlers structure */
struct SIG_hlist {
SIGTYPE (*handler)();
struct SIG_hlist *next;
};
/*
* Define array of lists of signal handlers. Note that this depends on
* the implementation to initialize each element to a null pointer.
*/
static struct SIG_hlist **SIG_handlers;
/* Define array of default signal vectors */
#ifdef POSIX
static struct sigaction *SIG_defaults;
#else
#ifdef BSD_SIGNALS
static struct sigvec *SIG_defaults;
#else
static SIGTYPE (**SIG_defaults)();
#endif
#endif
/* Critical section housekeeping */
static int SIG_crSectNest = 0; /* Nesting level */
#ifdef POSIX
static sigset_t SIG_crSectMask; /* Signal mask */
#else
static int SIG_crSectMask; /* Signal mask */
#endif
/*
* Initialize the signal handler arrays
*/
static int SIG_init()
{
int i;
#ifdef POSIX
sigset_t sigset_test;
#endif
if (SIG_defaults && SIG_handlers) /* already allocated */
return (0);
#ifdef POSIX
(void) sigfillset(&sigset_test);
for (i = 1; sigismember(&sigset_test, i) == 1; i++)
#ifdef BROKEN_SIGISMEMBER
if ( i >= NSIG )
break
#endif
;
if (i < SIGMAX)
i = SIGMAX;
i++;
if (!SIG_defaults)
SIG_defaults = (struct sigaction *)
calloc(i, sizeof(struct sigaction));
(void) sigemptyset(&SIG_crSectMask);
#else
i = SIGMAX+1;
#ifdef BSD_SIGNALS
if (!SIG_defaults)
SIG_defaults = (struct sigvec *)
calloc(i, sizeof(struct sigvec));
#else
if (!SIG_defaults)
SIG_defaults = (SIGTYPE (**)())
calloc(i, sizeof(SIGTYPE (**)()));
#endif
SIG_crSectMask = 0;
#endif
if (!SIG_handlers)
SIG_handlers = (struct SIG_hlist **)
calloc(i, sizeof(struct SIG_hlist *));
return (!SIG_defaults || !SIG_handlers);
}
/*
* The following invokes each signal handler in the reverse order in which
* they were registered.
*/
static SIGTYPE SIG_handle(sig)
int sig;
{
struct SIG_hlist *this;
/* Dispatch signal handlers */
this = SIG_handlers[sig];
while (this != (struct SIG_hlist *) NULL)
{
(*this->handler)(sig);
this = this->next;
}
return;
}
/*
* The following registers a signal handler. If the handler is already
* registered, it is not registered twice, nor is the order in which signal
* handlers are invoked changed. If this is the first signal handler
* registered for a given signal, the old sigvec structure is saved for
* restoration later.
*/
int SIG_register(sig,fn)
int sig;
SIGTYPE (*fn)();
{
int val;
struct SIG_hlist *this;
#ifdef POSIX
struct sigaction act;
sigset_t sigset_mask, sigset_omask;
#else
#ifdef BSD_SIGNALS
struct sigvec vec;
int mask;
#endif
#endif
/* Initialize */
if (SIG_init() != 0)
return (-1);
val = 0;
/* Block this signal while we look at handler chain */
#ifdef POSIX
(void) sigemptyset(&sigset_mask);
(void) sigaddset(&sigset_mask, sig);
(void) sigprocmask(SIG_BLOCK, &sigset_mask, &sigset_omask);
#else
#ifdef BSD_SIGNALS
mask = sigblock(sigmask(sig));
#endif
#endif
/* See if this handler was already registered */
this = SIG_handlers[sig];
while (this != (struct SIG_hlist *) NULL)
{
if (this->handler == fn) break;
this = this->next;
}
/* Register the new handler only if it is not already registered. */
if (this == (struct SIG_hlist *) NULL)
{
/*
* If this is the first handler registered for this signal,
* set up the signal handler dispatcher
*/
if (SIG_handlers[sig] == (struct SIG_hlist *) NULL)
{
#ifdef POSIX
act.sa_handler = SIG_handle;
(void) sigemptyset(&act.sa_mask);
act.sa_flags = 0;
val = sigaction(sig, &act, &SIG_defaults[sig]);
#else
#ifdef BSD_SIGNALS
bzero((char *)&vec, sizeof(vec));
vec.sv_handler = SIG_handle;
val = sigvec(sig, &vec, &SIG_defaults[sig]);
#else
if ((SIG_defaults[sig] = signal(sig, SIG_handle)) ==
(SIGTYPE (*)()) -1)
val = -1;
#endif
#endif
}
/* If not, register it */
if ((val == 0) && (this == (struct SIG_hlist *) NULL))
{
this = (struct SIG_hlist *)
malloc(sizeof(struct SIG_hlist));
if (this == NULL)
{
val = -1;
}
else
{
this->handler = fn;
this->next = SIG_handlers[sig];
SIG_handlers[sig] = this;
}
}
}
/* Unblock the signal */
#ifdef POSIX
(void) sigprocmask(SIG_SETMASK, &sigset_omask, NULL);
#else
#ifdef BSD_SIGNALS
(void) sigsetmask(mask);
#endif
#endif
return val;
}
/*
* The following deregisters a signal handler. If the last signal handler for
* a given signal is deregistered, the default sigvec information is restored.
*/
int SIG_deregister(sig,fn)
int sig;
SIGTYPE (*fn)();
{
int val;
struct SIG_hlist *this;
struct SIG_hlist *last;
#ifdef POSIX
sigset_t sigset_mask, sigset_omask;
#else
#ifdef BSD_SIGNALS
int mask;
#endif
#endif
/* Initialize */
if (SIG_init() != 0)
return (-1);
val = 0;
last = (struct SIG_hlist *) NULL;
/* Block this signal while we look at handler chain */
#ifdef POSIX
(void) sigemptyset(&sigset_mask);
(void) sigaddset(&sigset_mask, sig);
(void) sigprocmask(SIG_BLOCK, &sigset_mask, &sigset_omask);
#else
#ifdef BSD_SIGNALS
mask = sigblock(sigmask(sig));
#endif
#endif
/* Search for the signal handler */
this = SIG_handlers[sig];
while ((this != (struct SIG_hlist *) NULL) && (this->handler != fn))
{
last = this;
this = this->next;
}
/* If it was registered, remove it */
if (this != (struct SIG_hlist *) NULL)
{
if (last == (struct SIG_hlist *) NULL)
{
SIG_handlers[sig] = this->next;
}
else
{
last->next = this->next;
}
free((char *) this);
}
/* Restore default behavior if there are no registered handlers */
if (SIG_handlers[sig] == (struct SIG_hlist *) NULL)
{
#ifdef POSIX
val = sigaction(sig, &SIG_defaults[sig],
(struct sigaction *) NULL);
#else
#ifdef BSD_SIGNALS
val = sigvec(sig, &SIG_defaults[sig], (struct sigvec *) NULL);
#else
if (signal(sig, SIG_defaults[sig]) == (SIGTYPE (*)()) -1)
val = -1;
#endif
#endif
}
/* Unblock the signal */
#ifdef POSIX
(void) sigprocmask(SIG_SETMASK, &sigset_omask, NULL);
#else
#ifdef BSD_SIGNALS
(void) sigsetmask(mask);
#endif
#endif
return val;
}
/*
* The following begins a critical section.
*/
void SIG_beginCrSect()
{
if (SIG_init() == 0)
{
if (SIG_crSectNest == 0)
{
#ifdef POSIX
sigset_t sigset_mask;
(void) sigfillset(&sigset_mask);
(void) sigprocmask(SIG_SETMASK,
&sigset_mask, &SIG_crSectMask);
#else
#ifdef BSD_SIGNALS
SIG_crSectMask = sigblock(~0);
#else
/* TBD */
#endif
#endif
}
SIG_crSectNest++;
}
}
/*
* The following ends a critical section.
*/
void SIG_endCrSect()
{
if (SIG_init() == 0)
{
SIG_crSectNest--;
if (SIG_crSectNest == 0)
{
#ifdef POSIX
(void) sigprocmask(SIG_SETMASK, &SIG_crSectMask, NULL);
#else
#ifdef BSD_SIGNALS
(void) sigsetmask(SIG_crSectMask);
#else
/* TBD */
#endif
#endif
}
}
}

View File

@ -0,0 +1,39 @@
/* strdup.c -- return a newly allocated copy of a string
Copyright (C) 1990 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef STDC_HEADERS
#include <string.h>
#include <stdlib.h>
#else
char *malloc ();
char *strcpy ();
#endif
/* Return a newly allocated copy of STR,
or 0 if out of memory. */
char *
strdup (str)
char *str;
{
char *newstr;
newstr = (char *) malloc (strlen (str) + 1);
if (newstr)
strcpy (newstr, str);
return newstr;
}

View File

@ -0,0 +1,74 @@
/* strippath.c -- remove unnecessary components from a path specifier
Copyright (C) 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#if defined(STDC_HEADERS) || defined(USG)
#include <string.h>
#ifndef index
#define index strchr
#endif
#else
#include <strings.h>
#endif
#include <stdio.h>
#if __STDC__
static void remove_component(char *beginc, char *endc);
void strip_trailing_slashes(char *path);
#else
static void remove_component();
void strip_trailing_slashes();
#endif /* __STDC__ */
/* Remove unnecessary components from PATH. */
void
strip_path (path)
char *path;
{
int stripped = 0;
char *cp, *slash;
for (cp = path; (slash = index(cp, '/')) != NULL; cp = slash)
{
*slash = '\0';
if ((!*cp && (cp != path || stripped)) ||
strcmp(cp, ".") == 0 || strcmp(cp, "/") == 0)
{
stripped = 1;
remove_component(cp, slash);
slash = cp;
}
else
{
*slash++ = '/';
}
}
strip_trailing_slashes(path);
}
/* Remove the component delimited by BEGINC and ENDC from the path */
static void
remove_component (beginc, endc)
char *beginc;
char *endc;
{
for (endc++; *endc; endc++)
*beginc++ = *endc;
*beginc = '\0';
}

Some files were not shown because too many files have changed in this diff Show More