mirror of
https://git.FreeBSD.org/src.git
synced 2024-10-18 02:19:39 +00:00
Updated CVS
This commit is contained in:
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
3
gnu/usr.bin/cvs/Makefile
Normal file
3
gnu/usr.bin/cvs/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
SUBDIR = lib cvs mkmodules
|
||||
|
||||
.include <bsd.subdir.mk>
|
68
gnu/usr.bin/cvs/contrib/README
Normal file
68
gnu/usr.bin/cvs/contrib/README
Normal 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>
|
91
gnu/usr.bin/cvs/contrib/cln_hist.pl
Normal file
91
gnu/usr.bin/cvs/contrib/cln_hist.pl
Normal 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);
|
168
gnu/usr.bin/cvs/contrib/commit_prep.pl
Normal file
168
gnu/usr.bin/cvs/contrib/commit_prep.pl
Normal 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);
|
142
gnu/usr.bin/cvs/contrib/cvs_acls.pl
Normal file
142
gnu/usr.bin/cvs/contrib/cvs_acls.pl
Normal 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);
|
84
gnu/usr.bin/cvs/contrib/cvscheck
Normal file
84
gnu/usr.bin/cvs/contrib/cvscheck
Normal 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
|
53
gnu/usr.bin/cvs/contrib/cvscheck.man
Normal file
53
gnu/usr.bin/cvs/contrib/cvscheck.man
Normal 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
|
562
gnu/usr.bin/cvs/contrib/cvshelp.man
Normal file
562
gnu/usr.bin/cvs/contrib/cvshelp.man
Normal 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
|
116
gnu/usr.bin/cvs/contrib/descend
Normal file
116
gnu/usr.bin/cvs/contrib/descend
Normal 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
|
115
gnu/usr.bin/cvs/contrib/descend.man
Normal file
115
gnu/usr.bin/cvs/contrib/descend.man
Normal 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.
|
481
gnu/usr.bin/cvs/contrib/dirfns
Normal file
481
gnu/usr.bin/cvs/contrib/dirfns
Normal 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
|
104
gnu/usr.bin/cvs/contrib/log.pl
Normal file
104
gnu/usr.bin/cvs/contrib/log.pl
Normal 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);
|
331
gnu/usr.bin/cvs/contrib/log_accum.pl
Normal file
331
gnu/usr.bin/cvs/contrib/log_accum.pl
Normal 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;
|
87
gnu/usr.bin/cvs/contrib/mfpipe.pl
Normal file
87
gnu/usr.bin/cvs/contrib/mfpipe.pl
Normal 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;
|
119
gnu/usr.bin/cvs/contrib/pcl-cvs/ChangeLog
Normal file
119
gnu/usr.bin/cvs/contrib/pcl-cvs/ChangeLog
Normal 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.
|
||||
|
83
gnu/usr.bin/cvs/contrib/pcl-cvs/INSTALL
Normal file
83
gnu/usr.bin/cvs/contrib/pcl-cvs/INSTALL
Normal 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.
|
78
gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile
Normal file
78
gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile
Normal 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
|
14
gnu/usr.bin/cvs/contrib/pcl-cvs/README
Normal file
14
gnu/usr.bin/cvs/contrib/pcl-cvs/README
Normal 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
|
52
gnu/usr.bin/cvs/contrib/pcl-cvs/compile-all.el
Normal file
52
gnu/usr.bin/cvs/contrib/pcl-cvs/compile-all.el
Normal 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))
|
884
gnu/usr.bin/cvs/contrib/pcl-cvs/cookie.el
Normal file
884
gnu/usr.bin/cvs/contrib/pcl-cvs/cookie.el
Normal 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)))
|
298
gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll-debug.el
Normal file
298
gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll-debug.el
Normal 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)))))
|
386
gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll.el
Normal file
386
gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll.el
Normal 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))))
|
89
gnu/usr.bin/cvs/contrib/pcl-cvs/elib-node.el
Normal file
89
gnu/usr.bin/cvs/contrib/pcl-cvs/elib-node.el
Normal 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))))
|
6
gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-startup.el
Normal file
6
gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-startup.el
Normal 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)
|
1476
gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.el
Normal file
1476
gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.el
Normal file
File diff suppressed because it is too large
Load Diff
1367
gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.info
Normal file
1367
gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.info
Normal file
File diff suppressed because it is too large
Load Diff
1437
gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.texinfo
Normal file
1437
gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.texinfo
Normal file
File diff suppressed because it is too large
Load Diff
208
gnu/usr.bin/cvs/contrib/rcs-to-cvs
Normal file
208
gnu/usr.bin/cvs/contrib/rcs-to-cvs
Normal 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
|
234
gnu/usr.bin/cvs/contrib/rcslock.pl
Normal file
234
gnu/usr.bin/cvs/contrib/rcslock.pl
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
277
gnu/usr.bin/cvs/contrib/sccs2rcs
Normal file
277
gnu/usr.bin/cvs/contrib/sccs2rcs
Normal 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
|
18
gnu/usr.bin/cvs/cvs/Makefile
Normal file
18
gnu/usr.bin/cvs/cvs/Makefile
Normal 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
447
gnu/usr.bin/cvs/cvs/add.c
Normal 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
124
gnu/usr.bin/cvs/cvs/admin.c
Normal 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);
|
||||
}
|
135
gnu/usr.bin/cvs/cvs/checkin.c
Normal file
135
gnu/usr.bin/cvs/cvs/checkin.c
Normal 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);
|
||||
}
|
718
gnu/usr.bin/cvs/cvs/checkout.c
Normal file
718
gnu/usr.bin/cvs/cvs/checkout.c
Normal 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);
|
||||
}
|
380
gnu/usr.bin/cvs/cvs/classify.c
Normal file
380
gnu/usr.bin/cvs/cvs/classify.c
Normal 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
1229
gnu/usr.bin/cvs/cvs/commit.c
Normal file
File diff suppressed because it is too large
Load Diff
217
gnu/usr.bin/cvs/cvs/config.h
Normal file
217
gnu/usr.bin/cvs/cvs/config.h
Normal 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
|
100
gnu/usr.bin/cvs/cvs/create_adm.c
Normal file
100
gnu/usr.bin/cvs/cvs/create_adm.c
Normal 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
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
326
gnu/usr.bin/cvs/cvs/cvs.5
Normal 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
438
gnu/usr.bin/cvs/cvs/cvs.h
Normal 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
407
gnu/usr.bin/cvs/cvs/diff.c
Normal 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);
|
||||
}
|
488
gnu/usr.bin/cvs/cvs/entries.c
Normal file
488
gnu/usr.bin/cvs/cvs/entries.c
Normal 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);
|
||||
}
|
||||
}
|
272
gnu/usr.bin/cvs/cvs/find_names.c
Normal file
272
gnu/usr.bin/cvs/cvs/find_names.c
Normal 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);
|
||||
}
|
1373
gnu/usr.bin/cvs/cvs/history.c
Normal file
1373
gnu/usr.bin/cvs/cvs/history.c
Normal file
File diff suppressed because it is too large
Load Diff
227
gnu/usr.bin/cvs/cvs/ignore.c
Normal file
227
gnu/usr.bin/cvs/cvs/ignore.c
Normal 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);
|
||||
}
|
974
gnu/usr.bin/cvs/cvs/import.c
Normal file
974
gnu/usr.bin/cvs/cvs/import.c
Normal 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
522
gnu/usr.bin/cvs/cvs/lock.c
Normal 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
132
gnu/usr.bin/cvs/cvs/log.c
Normal 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);
|
||||
}
|
449
gnu/usr.bin/cvs/cvs/logmsg.c
Normal file
449
gnu/usr.bin/cvs/cvs/logmsg.c
Normal 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
444
gnu/usr.bin/cvs/cvs/main.c
Normal 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);
|
||||
}
|
810
gnu/usr.bin/cvs/cvs/modules.c
Normal file
810
gnu/usr.bin/cvs/cvs/modules.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
85
gnu/usr.bin/cvs/cvs/no_diff.c
Normal file
85
gnu/usr.bin/cvs/cvs/no_diff.c
Normal 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);
|
||||
}
|
147
gnu/usr.bin/cvs/cvs/parseinfo.c
Normal file
147
gnu/usr.bin/cvs/cvs/parseinfo.c
Normal 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
523
gnu/usr.bin/cvs/cvs/patch.c
Normal 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);
|
||||
}
|
1
gnu/usr.bin/cvs/cvs/patchlevel.h
Normal file
1
gnu/usr.bin/cvs/cvs/patchlevel.h
Normal file
@ -0,0 +1 @@
|
||||
#define PATCHLEVEL 0
|
1449
gnu/usr.bin/cvs/cvs/rcs.c
Normal file
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
102
gnu/usr.bin/cvs/cvs/rcs.h
Normal 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__ */
|
535
gnu/usr.bin/cvs/cvs/recurse.c
Normal file
535
gnu/usr.bin/cvs/cvs/recurse.c
Normal 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);
|
||||
}
|
219
gnu/usr.bin/cvs/cvs/release.c
Normal file
219
gnu/usr.bin/cvs/cvs/release.c
Normal 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);
|
||||
}
|
176
gnu/usr.bin/cvs/cvs/remove.c
Normal file
176
gnu/usr.bin/cvs/cvs/remove.c
Normal 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
169
gnu/usr.bin/cvs/cvs/repos.c
Normal 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
403
gnu/usr.bin/cvs/cvs/rtag.c
Normal 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);
|
||||
}
|
230
gnu/usr.bin/cvs/cvs/status.c
Normal file
230
gnu/usr.bin/cvs/cvs/status.c
Normal 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
263
gnu/usr.bin/cvs/cvs/tag.c
Normal 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
1028
gnu/usr.bin/cvs/cvs/update.c
Normal file
File diff suppressed because it is too large
Load Diff
224
gnu/usr.bin/cvs/cvs/vers_ts.c
Normal file
224
gnu/usr.bin/cvs/cvs/vers_ts.c
Normal 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;
|
||||
}
|
11
gnu/usr.bin/cvs/cvs/version.c
Normal file
11
gnu/usr.bin/cvs/cvs/version.c
Normal 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
1073
gnu/usr.bin/cvs/doc/cvs.ms
Normal file
File diff suppressed because it is too large
Load Diff
21
gnu/usr.bin/cvs/examples/commitinfo
Normal file
21
gnu/usr.bin/cvs/examples/commitinfo
Normal 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
|
30
gnu/usr.bin/cvs/examples/editinfo
Normal file
30
gnu/usr.bin/cvs/examples/editinfo
Normal 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"
|
20
gnu/usr.bin/cvs/examples/loginfo
Normal file
20
gnu/usr.bin/cvs/examples/loginfo
Normal 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
|
566
gnu/usr.bin/cvs/examples/modules
Normal file
566
gnu/usr.bin/cvs/examples/modules
Normal 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
|
18
gnu/usr.bin/cvs/examples/rcsinfo
Normal file
18
gnu/usr.bin/cvs/examples/rcsinfo
Normal 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
|
8
gnu/usr.bin/cvs/lib/Makefile
Normal file
8
gnu/usr.bin/cvs/lib/Makefile
Normal 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>
|
91
gnu/usr.bin/cvs/lib/Makefile.in
Normal file
91
gnu/usr.bin/cvs/lib/Makefile.in
Normal 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
|
191
gnu/usr.bin/cvs/lib/alloca.c
Normal file
191
gnu/usr.bin/cvs/lib/alloca.c
Normal 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));
|
||||
}
|
||||
}
|
||||
|
83
gnu/usr.bin/cvs/lib/argmatch.c
Normal file
83
gnu/usr.bin/cvs/lib/argmatch.c
Normal 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);
|
||||
}
|
36
gnu/usr.bin/cvs/lib/dup2.c
Normal file
36
gnu/usr.bin/cvs/lib/dup2.c
Normal 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
193
gnu/usr.bin/cvs/lib/error.c
Normal 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 */
|
183
gnu/usr.bin/cvs/lib/fnmatch.c
Normal file
183
gnu/usr.bin/cvs/lib/fnmatch.c
Normal 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;
|
||||
}
|
45
gnu/usr.bin/cvs/lib/fnmatch.h
Normal file
45
gnu/usr.bin/cvs/lib/fnmatch.h
Normal 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 */
|
72
gnu/usr.bin/cvs/lib/ftruncate.c
Normal file
72
gnu/usr.bin/cvs/lib/ftruncate.c
Normal 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
|
889
gnu/usr.bin/cvs/lib/getdate.y
Normal file
889
gnu/usr.bin/cvs/lib/getdate.y
Normal 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) */
|
604
gnu/usr.bin/cvs/lib/getopt.c
Normal file
604
gnu/usr.bin/cvs/lib/getopt.c
Normal 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 */
|
102
gnu/usr.bin/cvs/lib/getopt.h
Normal file
102
gnu/usr.bin/cvs/lib/getopt.h
Normal 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
|
166
gnu/usr.bin/cvs/lib/getopt1.c
Normal file
166
gnu/usr.bin/cvs/lib/getopt1.c
Normal 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 */
|
31
gnu/usr.bin/cvs/lib/getwd.c
Normal file
31
gnu/usr.bin/cvs/lib/getwd.c
Normal 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
338
gnu/usr.bin/cvs/lib/hash.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
77
gnu/usr.bin/cvs/lib/hash.h
Normal file
77
gnu/usr.bin/cvs/lib/hash.h
Normal 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
125
gnu/usr.bin/cvs/lib/mkdir.c
Normal 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;
|
||||
}
|
||||
}
|
212
gnu/usr.bin/cvs/lib/myndbm.c
Normal file
212
gnu/usr.bin/cvs/lib/myndbm.c
Normal 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 */
|
44
gnu/usr.bin/cvs/lib/myndbm.h
Normal file
44
gnu/usr.bin/cvs/lib/myndbm.h
Normal 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
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
479
gnu/usr.bin/cvs/lib/regex.h
Normal 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:
|
||||
*/
|
68
gnu/usr.bin/cvs/lib/rename.c
Normal file
68
gnu/usr.bin/cvs/lib/rename.c
Normal 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;
|
||||
}
|
412
gnu/usr.bin/cvs/lib/sighandle.c
Normal file
412
gnu/usr.bin/cvs/lib/sighandle.c
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
39
gnu/usr.bin/cvs/lib/strdup.c
Normal file
39
gnu/usr.bin/cvs/lib/strdup.c
Normal 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;
|
||||
}
|
74
gnu/usr.bin/cvs/lib/strippath.c
Normal file
74
gnu/usr.bin/cvs/lib/strippath.c
Normal 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
Loading…
Reference in New Issue
Block a user