Update to use the cvs-1.8.1 sources from src/contrib/cvs

This commit is contained in:
Peter Wemm 1996-08-20 23:58:03 +00:00
parent 7e0b7d4a87
commit 8787dbbafe
154 changed files with 125 additions and 76724 deletions

View file

@ -1,248 +0,0 @@
* `cvs checkout -d nested/dir/path <module>' just doesn't work. The
simpler version -- `cvs checkout -d single-dir <module>' works,
however.
* CVS leaves .#mumble files around when a conflict occurs. (Note:
this is intentional and is documented in doc/cvs.texinfo. Of course
whether it is a good idea is a separate question).
* pcl-cvs doesn't like it when you try to check in a file which isn't
up-to-date. The messages produced by the server perhaps don't match
what pcl-cvs is looking for.
* From: Roland McGrath <roland@gnu.ai.mit.edu>
To: Cyclic CVS Hackers <cyclic-cvs@cyclic.com>
Subject: weird bug
Date: Sat, 25 Mar 1995 16:41:41 -0500
X-Windows: Even your dog won't like it.
I just noticed some droppings on my disk from what must be a pretty weird
bug in remote CVS.
In my home directory on a repository machine I use, I find:
drwxr-xr-x 4 roland staff 512 Mar 7 14:08 cvs-serv28962
drwxr-xr-x 4 roland staff 512 Mar 7 14:11 cvs-serv28978
drwxr-xr-x 4 roland staff 512 Mar 7 15:13 cvs-serv29141
OK, so these are leftover cruft from some cvs run that got aborted.
Well, it should clean up after itself, but so what.
The last one is pretty dull; the real weirdness is the contents of the
first two directories.
duality 77 # ls -RF cvs-serv28978/
CVS/ cvs-serv28978/
cvs-serv28978/CVS:
Entries Repository
cvs-serv28978/cvs-serv28978:
arpa/
cvs-serv28978/cvs-serv28978/arpa:
CVS/ cvs-serv28978/
cvs-serv28978/cvs-serv28978/arpa/CVS:
Entries Repository
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978:
assert/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert:
CVS/ cvs-serv28978/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/CVS:
Entries Repository
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978:
bare/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare:
CVS/ cvs-serv28978/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/CVS:
Entries Repository
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978:
conf/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf:
CVS/ cvs-serv28978/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/CVS:
Entries Repository
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978:
crypt/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt:
CVS/ cvs-serv28978/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/CVS:
Entries Repository
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978:
csu/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu:
CVS/ cvs-serv28978/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu/CVS:
Entries Repository
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu/cvs-serv28978:
ctype/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu/cvs-serv28978/ctype:
CVS/ cvs-serv28978/
[...]
ls: cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu/cvs-serv28978/ctype/cvs-serv28978/dirent/cvs-serv28978/elf/cvs-serv28978/gnu/cvs-serv28978/gnulib/cvs-serv28978/grp/cvs-serv28978/hurd/cvs-serv28978/hurd/hurd/cvs-serv28978/inet/cvs-serv28978/inet/arpa/cvs-serv28978/inet/netinet[...]/cvs-serv28978/posix/cvs-serv28978/posix/glob/cvs-serv28978/posix/gnu/cvs-serv28978/posix/sys/cvs-serv28978/protocols/cvs-serv28978/pwd/cvs-serv28978/resolv/cvs-serv28978/resolv/arpa/cvs-serv28978/resolv/sys/cvs-serv28978/resource/cvs-serv28978/resource/sys/cvs-serv28978/rpc/cvs-serv28978/setjmp/cvs-serv28978/signal/cvs-serv28978/signal/sys/cvs-serv28978/socket/cvs-serv28978/socket: File name too long
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu/cvs-serv28978/ctype/cvs-serv28978/dirent/cvs-serv28978/elf/cvs-serv28978/gnu/cvs-serv28978/gnulib/cvs-serv28978/grp/cvs-serv28978/hurd/cvs-serv28978/hurd/hurd/cvs-serv28978/inet/cvs-serv28978/inet/arpa/cvs-serv28978/inet/netinet[...]/cvs-serv28978/posix/glob/cvs-serv28978/posix/gnu/cvs-serv28978/posix/sys/cvs-serv28978/protocols/cvs-serv28978/pwd/cvs-serv28978/resolv/cvs-serv28978/resolv/arpa/cvs-serv28978/resolv/sys/cvs-serv28978/resource/cvs-serv28978/resource/sys/cvs-serv28978/rpc/cvs-serv28978/setjmp/cvs-serv28978/signal/cvs-serv28978/signal/sys/cvs-serv28978/socket/cvs-serv28978:
* From: billr@mpd.tandem.com (Bill Robertson)
Subject: Problem with rtag and the -D option
Date: Fri, 17 Mar 1995 10:53:29 -0600 (CST)
I have been trying to use the -D option to specify a date for tagging, but
rtag does not recognize the -D option. It is documented to do so and I've
tested the use of -D with cvs update and cvs diff and it works fine there.
* We need some version numbers really badly. Are there some
(and Charles Hannum is just not including them in his reports), or do
we simply have no reliable way to distinguish between the various
versions of rCVS people on the list are running?
Now that I think of it, version numbers present a problem when
people can update their sources anytime and rebuild. I think the
solution is to increment a minor version number *every* time a bug is
fixed, so we can identify uniquely what someone is running when they
submit a report. This implies recording the version increments in the
ChangeLog; that way we can just look to see where a particular version
lies in relation to the flow of changing code.
Should we be doing same with Guppy? I guess not -- it's only
important when you have people who are updating directly from your
development tree, which is the case with the remote-cvs folks.
Thoughts?
* (Charles Hannum <mycroft@ai.mit.edu>) has these bugs:
I just tossed remote CVS at a fairly large source tree that I already
had, and noticed a few problems:
1) server.c assumes that /usr/tmp is a valid default for the place to
store files uploaded from the client. There are a number of systems
that now use /var/tmp. These should probably be detected by autoconf.
2) The server deals rather ungracefully with the tmp directory
becoming full.
3) There's some oddness with relative paths in Repository files that
causes the directory prefix to be added twice; e.g. if I have CVSROOT
set to `machine:/this/dir', and I try to update in a directory whose
Repository file says `src/bin', the server looks in
`/this/dir/machine:/this/dir/src/bin'.
* From: "Charles M. Hannum" <mycroft@ai.mit.edu>
To: jimb@duality.gnu.ai.mit.edu, roland@duality.gnu.ai.mit.edu
Subject: Serious flaw in remote CVS
Date: Wed, 22 Feb 1995 20:54:36 -0500
I just found a major flaw in the current implementation. Because the
sockets are not changed to non-blocking mode, write(2)s can hang. In
some cases, this happens on both sides at the same time, with the
socket buffers full in both directions. This causes a deadlock,
because both processes are stuck in I/O wait and thus never drain
their input queues.
Until this is fixed, I can't use it. I'll look at the problem myself
at some point, but I don't know when.
From: "Charles M. Hannum" <mycroft@ai.mit.edu>
To: remote-cvs@cyclic.com
Cc: jimb@totoro.bio.indiana.edu
Subject: Re: forwarded message from Charles M. Hannum
Date: Wed, 22 Feb 1995 22:07:07 -0500
FYI, this happened because the tmp directory on the server became
full. Somehow the server started interpreting the files the client
was sending as commands, and started spewing tons of errors.
Apparently the errors are sent with blocking I/O, or something, and
thus allowed the deadlock to happen.
* From: "Charles M. Hannum" <mycroft@ai.mit.edu>
To: remote-cvs@cyclic.com
Subject: Regarding that relative path problem
Date: Thu, 23 Feb 1995 02:41:51 -0500
This is actually more serious. If you have `bar.com:/foo' as your CVS
root directory, then:
1) When you check things out, the Repository files will contain
`/foo/...' (i.e. without the machine name), which makes little sense.
2) If you instead have a relative path, when the Repository file is
read, `bar.com:/foo' is prepended. This is sent to the server, but
confuses it, because it's not expecting the machine name to be
prepended.
A slightly klugy fix would be to have the client prepend the machine
name when writing a new Repository file, and strip it off before
sending one to the server. This would be backward-compatible with the
current arrangement.
* From: "Charles M. Hannum" <mycroft@ai.mit.edu>
To: remote-cvs@cyclic.com
Subject: Still one more bug
Date: Sat, 25 Feb 1995 17:01:15 -0500
mycroft@duality [1]; cd /usr/src/lib/libc
mycroft@duality [1]; cvs diff -c2 '-D1 day ago' -Dnow
cvs server: Diffing .
cvs server: Diffing DB
cvs [server aborted]: could not chdir to DB: No such file or directory
mycroft@duality [1];
`DB' is an old directory, which no longer has files in it, and is
removed automatically when I use the `-P' option to checkout.
This error doesn't occur when run locally.
P.S. Is anyone working on fixing these bugs?
* From: Roland McGrath <roland@gnu.ai.mit.edu>
To: Cyclic CVS Hackers <cyclic-cvs@cyclic.com>
Subject: bizarre failure mode
Date: Tue, 7 Mar 95 14:17:28 -0500
This is pretty weird:
CVS_SERVER='TMPDIR=. /usr/local/bin/cvs' ../cvs-build/src/cvs update -q
cvs [server aborted]: could not get working directory: Result too large
[Exit 1]
asylum 29 % grep 'Result too large' /usr/include/sys/errno.h
#define ERANGE 34 /* Result too large */
Now, getcwd fails with ERANGE when the buffer is too small. But I don't
know why that would be the case; I don't think there are exceptionally long
directory names involved. It would be robust to notice ERANGE and use a
bigger buffer. But I suspect something weirder is going on.
The repository in question in duality.gnu.ai.mit.edu:/gd4/gnu/cvsroot/libc.
Send me a PGP-signed message if you want the password to use the machine
where the problem showed up.

File diff suppressed because it is too large Load diff

View file

@ -1,356 +0,0 @@
#ident "$CVSid$"
First, read the README file. If you're still happy...
CVS has been tested on the following platforms. The most recent
version of CVS reported to have been tested is indicated, but more
recent versions of CVS probably will work too. Please send updates to
this list to info-cvs@prep.ai.mit.edu.
Alpha:
DEC Alpha running OSF/1 version 1.3 using cc (about 1.4A2)
DEC Alpha running OSF/1 version 2.0 (1.4.90)
DEC Alpha running OSF/1 version 2.1 (about 1.4A2)
DEC Alpha running OSF/1 version 3.0 (1.5.95) (footnote 7)
HPPA:
HP 9000/710 running HP-UX 8.07A using gcc (about 1.4A2)
HP 9000/715 running HP-UX 9.01 (1.6)
HPPA 1.1 running HP-UX A.09.03 (1.5.95) (footnote 8)
NextSTEP 3.3 (1.4.92, a few tweaks needed)
i386 family:
Gateway P5-66 (pentium) running Solaris 2.4 using gcc (about 1.4A2)
PC Clone running UnixWare v1.1.1 using gcc (about 1.4A2)
PC Clone running ISC 4.0.1 (1.5.94)
PC Clone running Fintronic Linux 1.2.5 (1.5)
PC Clone running BSDI 2.0 (1.4.93) (footnote 5)
PC Clone running Windows NT 3.51 (1.6.2 client-only)
FreeBSD 2.0.5, i486, gcc (1.5.95)
NextSTEP 3.3 (1.4.92, a few tweaks needed)
SCO Unix 3.2.4.2 (1.4.93) (footnote 4)
SCO OpenServer 5.0.0, "CC='cc -b elf' configure"
m68k:
Sun 3 running SunOS 4.1.1_U1 w/ bundled K&R /usr/5bin/cc (1.6)
NextSTEP 3.3 (1.4.92, a few tweaks needed)
m88k:
Data General AViiON running dgux 5.4R2.10 (1.5)
Harris Nighthawk 5800 running CX/UX 7.1 (1.5) (footnote 6)
MIPS:
DECstation running Ultrix 4.2a (1.4.90)
DECstation running Ultrix 4.3 (1.5)
SGI running Irix 4.0.5H using gcc and cc (about 1.4A2) (footnote 2)
SGI running Irix 5.3 (1.4.93)
SGI running Irix-6 (about 1.4.90) (footnote 3)
Siemens-Nixdorf RM600 running SINIX-Y (1.6)
PowerPC or RS/6000:
IBM RS/6000 running AIX 3.2.5 (cc=xlc, CVS 1.5)
IBM RS/6000 running AIX 4.1 using gcc and cc (about 1.4A2) (footnote 1)
SPARC:
Sun SPARC running SunOS 4.1.4 w/ bundled K&R /usr/5bin/cc (1.6)
Sun SPARC running SunOS 4.1.3, 4.1.2, and 4.1.1 (1.5)
Sun SPARC running SunOS 4.1.3, w/ bundled K&R cc (1.5.94)
Sun SPARCstation 10 running Solaris 2.3 using gcc and cc (about 1.4A2)
Sun SPARCstation running Solaris 2.4 using gcc and cc (about 1.5.91)
Sun SPARC running Solaris 2.5 (2.5 beta?) (1.6.2)
NextSTEP 3.3 (1.4.92, a few tweaks needed)
(footnote 1)
AIX 4.1 systems fail to run "configure" due to bugs in their
"/bin/sh" implementation. You might want to try feeding the
configure script to "bash" ported to AIX 4.1. (about 1.4A2).
(footnote 2)
Some Irix 4.0 systems may core dump in malloc while running
CVS. We believe this is a bug in the Irix malloc. You can
workaround this bug by linking with "-lmalloc" if necessary.
(about 1.4A2).
(footnote 3)
There are some warnings about pointer casts which can safely be
ignored. (about 1.4.90).
(footnote 4) Comment out the include of sys/time.h in src/server.c. (1.4.93)
You also may have to make sure TIME_WITH_SYS_TIME is undef'ed.
(footnote 5) Change /usr/tmp to /var/tmp in src/server.c (2 places) (1.4.93).
(footnote 6) Build in ucb universe with COFF compiler tools. Put
/usr/local/bin first in PATH while doing a configure, make
and install of GNU diffutils-2.7, rcs-5.7, then cvs-1.5.
(footnote 7) Manoj Srivastava <srivasta@pilgrim.umass.edu> reports
success with this configure command:
CC=cc CFLAGS='-O2 -Olimit 2000 -std1' ./configure --verbose alpha-dec-osf
(footnote 8) Manoj Srivastava <srivasta@pilgrim.umass.edu> reports
success with this configure command:
CC=cc CFLAGS='+O2 -Aa -D_HPUX_SOURCE' ./configure --verbose hppa1.1-hp-hpux
-------------------------------------------------------------------------------
Installation under Unix:
1) Run "configure":
$ ./configure
You can specify an alternate destination to override the default with
the --prefix option:
$ ./configure --prefix=/usr/local/gnu
or some path that is more appropriate for your site. The default prefix
value is "/usr/local", with binaries in sub-directory "bin", manual
pages in sub-directory "man", and libraries in sub-directory "lib".
This release of CVS also requires RCS commands to be installed in
the user's PATH (or a path you have configured in src/options.h).
If you don't have RCS, you will need to get it from GNU as well. It
is best to get the version 5.7 (or later) version of RCS, available
from prep.ai.mit.edu in the file pub/gnu/rcs-5.7.tar.gz. It is best
(although not essential) to avoid RCS versions 5.6.[5-7] beta
because the rcsmerge therein defaults to -A instead of -E which
affects the way CVS handles conflicts (this is fixed in RCS 5.6.8
and RCS 5.7).
Along with RCS, you will want to run GNU diffutils. This will allow
revision control of files with binary data (a real nice feature).
You will need at least version 1.15 of GNU diff for this to work.
The current version of GNU diffutils is 2.7, and it is also
available from prep.ai.mit.edu in the file pub/gnu/diffutils-2.7.tar.gz.
WARNING: Be sure that you (have) configure(d) RCS to work correctly
with GNU diff to avoid other configuration problems.
Configure will attempt to discern the location of your most capable
version of diff, and tries to find the GNU Diffutils version first.
You can explicitly tell configure to use the diffutils that's
installed in the same place you intend to install CVS:
$ ./configure --with-diffutils
Or, if you've installed it somewhere else, you can give configure
the full pathname:
$ ./configure --with-diffutils=/usr/gnu/bin/diff
Configure will also try to find a version of grep that supports the
'-s' option, and tries to find the GNU Grep version first. You can
similarly tell it where to find GNU Grep:
$ ./configure --with-gnugrep
$ ./configure --with-gnugrep=/usr/gnu/bin/grep
If you are using the remote client, you will need a version of patch
which understands unidiffs (such as any recent version of GNU
patch). Configure does not yet check to see if you've got this, so
be careful!
NOTE: The configure program will cache the results of the previous
configure execution. If you need to re-run configure from scratch, you
may need to run "make distclean" first to remove the cached
configuration information.
Try './configure --help' for further information on its usage.
NOTE ON CVS's USE OF NDBM:
By default, CVS uses some built-in ndbm emulation code to allow
CVS to work in a heterogeneous environment. However, if you have
a very large modules database, this may not work well. You will
need to edit src/options.h to turn off the MY_NDBM #define and
re-run configure. If you do this, the following comments apply.
If not, you may safely skip these comments.
If you configure CVS to use the real ndbm(3) libraries and
you do not have them installed in a "normal" place, you will
probably want to get the GNU version of ndbm (gdbm) and install
that before running the CVS configure script. Be aware that the
GDBM 1.5 release does NOT install the <ndbm.h> header file included
with the release automatically. You may have to install it by hand.
If you configure CVS to use the ndbm(3) libraries, you cannot
compile CVS with GNU cc (gcc) on Sun-4 SPARC systems. However, gcc
2.0 may have fixed this limitation if -fpcc-struct-return is
defined. When using gcc on other systems to compile CVS, you *may*
need to specify the -fpcc-struct-return option to gcc (you will
*know* you have to if "cvs checkout" core dumps in some ndbm
function). You can do this as follows:
$ CC='gcc -fpcc-struct-return' ./configure
for sh, bash, and ksh users and:
% setenv CC 'gcc -fpcc-struct-return'
% ./configure
for csh and tcsh users.
END OF NOTE FOR NDBM GUNK.
2) Edit src/options.h. Appropriate things to look at may be the
invocation locations of programs like DIFF, GREP, RM, and SORT.
Also glance at the default values for the environment variables
that CVS uses, in particular, the RCSBIN variable, which holds the
path to where the RCS programs live on your system. The
likelihood is that you don't have to change anything here, except
perhaps adding the -a option to DIFF if you are using GNU diff.
3) Try to build it:
$ make
This will (hopefully) make the needed CVS binaries within the "src"
directory. If something fails for your system, using the "cvsbug"
script submit your "config.status" file together with your host
type, operating system and compiler information, make output, and
anything else you think will be helpful.
You may also wish to validate the correctness of the new binary by
running the regression tests:
$ make check
Note that if your /bin/sh doesn't support shell functions, you'll
have to try something like this, where "/bin/sh5" is replaced by the
pathname of a shell which handles normal shell functions:
$ make SHELL=/bin/sh5 check
WARNING: This test can take quite a while to run, esp. if your
disks are slow or over-loaded.
If you receive any un-expected output from the regression tests,
using the "cvsbug" script please submit your "config.status" file,
together with your host type, operating system and compiler
information, the contents of /tmp/cvs-sanity/check.log, and any
"make check" output.
4) Install the binaries/documentation:
$ make install
Depending on your installation's configuration, you may need to be
root to do this.
5) Take a look at the CVS documentation.
$ man cvs
and
$ info cvs
See what it can do for you, and if it fits your environment (or can
possibly be made to fit your environment). If things look good,
continue on...
6) 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. Note that this should be some shared directory for your
site. It should probably be auto-mounted, if you're running NFS.
Say you choose "/src/master" as the root of your source repository.
Run the "cvsinit" script to help you set it up. It will ask you to
enter the path to your CVSROOT area. You would enter /src/master in
this example.
$ ./cvsinit
The cvsinit script will setup a reasonable CVSROOT area to start with.
It is also valuable to folks who already have a CVSROOT area setup from
using earlier releases of CVS. It assumes that you have installed CVS
already (step 4) and that the RCS programs (co and ci) are in your
PATH. There are many ways to customize CVS for your site. Read the
cvs(5) manual page when you get the chance.
7) Have all users of the CVS system set the 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 user's ~/.profile, ~/.bash_profile file; or in the
site-wide /etc/profile:
CVSROOT=/src/master; export CVSROOT
for sh/bash/ksh users, or place the following commands in the user's
~/.cshrc, ~/.login, or /etc/chsrc file:
setenv CVSROOT /src/master
for csh/tcsh users. If these environment variables are not already set
in your current shell, set them now (or source the login script you
just edited). You will need to have the CVSROOT environment variable
set to continue on to the next step.
8) It might be a good idea to jump right in and put the CVS distribution
directly under CVS control. From within the top-level directory of the
CVS distribution (the one that contains this README file) do the
following commands:
$ make distclean
$ cvs import -m 'CVS 1.6 distribution' cvs CVS CVS-1_6
9) Having done step 8, one should be able to checkout a fresh copy of the
CVS distribution and hack away at the sources with the following command:
$ cd
$ cvs checkout cvs
This will make the directory "cvs" in your current directory and
populate it with the appropriate CVS files and directories.
10) Remember to edit the modules file manually when sources are checked in
with "cvs import" or "cvs add". A copy of the modules file for editing
can usually be retrieved with the "cvs checkout modules" command, and
definitely with the "cvs checkout CVSROOT" command. See cvs(5).
11) Read the NEWS file to see what's new.
12) Hack away.
-------------------------------------------------------------------------------
Detailed information about your interaction with "configure":
The "configure" script and its interaction with its options and the
environment is described here. For more detailed documentation about
"configure", please refer to the GNU Autoconf documentation.
Supported options are:
--srcdir=DIR Useful for compiling on many different
machines sharing one source tree.
--prefix=DIR The root of where to install the
various pieces of CVS (/usr/local).
--exec_prefix=DIR If you want executables in a
host-dependent place and shared
things in a host-independent place.
--with-diffutils[=PATH] Assume use of GNU diffutils is possible.
--with-gnugrep[=PATH] Assume use of GNU grep is possible.
The following environment variables override configure's default
behaviour:
CC If not set, tries to use gcc first,
then cc. Also tries to use "-g -O"
as options, backing down to -g
alone if that doesn't work.
INSTALL If not set, tries to use "install", then
"./install-sh" as a final choice.
RANLIB If not set, tries to determine if "ranlib"
is available, choosing "echo" if it doesn't
appear to be.
YACC If not set, tries to determine if "bison"
is available, choosing "yacc" if it doesn't
appear to be.
-------------------------------------------------------------------------------
Installation under Windows NT:
You may find interesting information in windows-NT/README.
1) Using Microsoft Visual C++ version 2.1, open the project `cvsnt.mak',
in the top directory of the CVS distribution.
2) Choose "Build cvs.exe" from the "Project" menu.
3) MSVC will place the executable file cvs.exe in WinDebug, or whatever
your target directory is.
-------------------------------------------------------------------------------

View file

@ -1,60 +0,0 @@
Low-priority bugs go here. We don't have many yet -- everything is
high-priority at the moment. :-)
* From: Jeff Johnson <jbj@brewster.JBJ.ORG>
To: cyclic-cvs@cyclic.com
Subject: Named_Root assumes . on server
Date: Wed, 17 May 1995 11:04:53 -0400 (EDT)
Problem:
On server, Name_Root() attempts (aggressively) to set CVSADM_Root.
If ~/CVS/Root exists (wrto rsh login), then CVSADM_Root will be
initialized from that file. The sanity check between the root
repository and the invocation will fail if the two values are not
coincidentally the same.
Workaround:
There's a zillion ways to fix this bugture/featurelet. My current
workaround is to remove ~/CVS/Root on the server. I shall attempt
a better fix as soon as I can determine what appears politically
correct. IMHO, the CVS/Root stuff (and getenv("CVSROOT") also) is
a bit fragile and tedious in an rcmd() driven CCVS environment.
* (Jeff Johnson <jbj@jbj.org>)
I tried a "cvs status -v" and received the following:
? CVS
? programs/CVS
? tests/CVS
cvs server: Examining .
===================================================================
File: Install.dec Status: Up-to-date
...
I claim that CVS dirs should be ignored.
* I sometimes get this message:
Could not look up address for your host. Permission denied.
cvs [update aborted]: premature end of file from server
The client's response should be cleaned up.
* In the gb-grep module, update-ChangeLog (and therefore, I assume,
rcs2log) truncates file names --- I get entries for things called
ring/lenstring.h instead of lenstring/lenstring.h.
* On remote checkout, files don't have the right time/date stamps in
the CVS/Entries files. Doesn't look like the C/S protocol has any
way to send this information along (according to cvsclient.texi).
Perhaps we can spiff it up a bit by using the conflict field for the
stamp on the checkout/update command. Please note that this really
doesn't do very much for us even if we get it done.
* Does the function that lists the available modules in the repository
belong under the "checkout" function? Perhaps it is more logically
grouped with the "history" function or we should create a new "info"
function?

View file

@ -1,5 +1,5 @@
# $Id: Makefile,v 1.6 1995/04/14 15:15:27 nate Exp $
# $Id: Makefile,v 1.7 1995/12/10 22:58:29 peter Exp $
SUBDIR = lib cvs mkmodules contrib cvsbug cvsinit doc examples
SUBDIR = lib cvs contrib cvsbug doc tools
.include <bsd.subdir.mk>

View file

@ -1,3 +1,7 @@
.if !defined(CVSDIR)
CVSDIR= $(.CURDIR)/../../../../contrib/cvs
.if exists(${.OBJDIR}/../lib)
LIBDESTDIR= ${.OBJDIR}/../lib
.else
@ -6,3 +10,9 @@ LIBDESTDIR= ${.CURDIR}/../lib
LDDESTDIR= -L${LIBDESTDIR}
LIBCVS= ${LIBDESTDIR}/libcvs.a
.if exists(${.CURDIR}/../../Makefile.inc)
.include "${.CURDIR}/../../Makefile.inc"
.endif
.endif

View file

@ -1,863 +0,0 @@
Changes since 1.6:
* RCS keyword "Name" supported for "cvs update -r <tag>" and "cvs
checkout -r <tag>".
* If there is a group whose name matches a compiled in value which
defaults to "cvsadmin", only members of that group can use "cvs
admin".
* CVS now sets the modes of files in the repository based on the
CVSUMASK environment variable or a compiled in value defaulting to
002. This way other developers will be able to access the files in
the repository regardless of the umask of the developer creating them.
* The command name .cvsrc now matches the official name of the
command, not the one (possibly an alias) by which it was invoked. If
you had previously relied on "cvs di" and "cvs diff" using different
options, instead use a shell function or alias (for example "alias
cvsdi='cvs diff -u'").
Changes from 1.5 to 1.6:
* Del updated the man page to include all of the new features
of CVS 1.6.
* "cvs tag" now supports a "-r | -D" option for tagging an already
tagged revision / specific revision of a file.
* There is a "taginfo" file in CVSROOT that supports filtering and
recording of tag operations.
* Long options support added, including --help and --version options.
* "cvs release" no longer cares whether or not the directory being
released has an entry in the `modules' file.
* The modules file now takes a -e option which is used instead of -o
for "cvs export". If your modules file has a -o option which you want
to be used for "cvs export", change it to specify -e as well as -o.
* "cvs export" now takes a -k option to set RCS keyword expansion.
This way you can export binary files. If you want the old behavior,
you need to specify -kv.
* "cvs update", "cvs rdiff", "cvs checkout", "cvs import", "cvs
release", "cvs rtag", and "cvs tag" used to take -q and -Q options
after the command name (e.g. "cvs update -q"). This was confusing
because other commands, such as "cvs ci", did not. So the options
after the command name have been removed and you must now specify, for
example, "cvs -q update", which has been supported since CVS 1.3.
* New "wrappers" feature. This allows you to set a hook which
transforms files on their way in and out of cvs (apparently on the
NeXT there is some particular usefulness in tarring things up in the
repository). It also allows you to declare files as merge-by-copy
which means that instead of trying to merge the file, CVS will merely
copy the new version. There is a CVSROOT/cvswrappers file and an
optionsl ~/.cvswrappers file to support this feature.
* You can set CVSROOT to user@host:dir, not just host:dir, if your
username on the server host is different than on the client host.
* VISUAL is accepted as well as EDITOR.
* $CVSROOT is expanded in *info files.
Changes from 1.4A2 to 1.5:
* Remote implementation. This is very helpful when collaborating on a
project with someone across a wide-area network. This release can
also be used locally, like other CVS versions, if you have no need for
remote access.
Here are some of the features of the remote implementation:
- It uses reliable transport protocols (TCP/IP) for remote repository
access, not NFS. NFS is unusable over long distances (and sometimes
over short distances)
- It transfers only those files that have changed in the repository or
the working directory. To save transmission time, it will transfer
patches when appropriate, and can compress data for transmission.
- The server never holds CVS locks while waiting for a reply from the client;
this makes the system robust when used over flaky networks.
The remote features are documented in doc/cvsclient.texi in the CVS
distribution, but the main doc file, cvs.texinfo, has not yet been
updated to include the remote features.
* Death support. See src/README-rm-add for more information on this.
* Many speedups, especially from jtc@cygnus.com.
* CVS 1.2 compatibility code has been removed as a speedup. If you
have working directories checked out by CVS 1.2, CVS 1.3 or 1.4A2 will
try to convert them, but CVS 1.5 and later will not (if the working
directory is up to date and contains no extraneous files, you can just
remove it, and then check out a new working directory). Likewise if
your repository contains a CVSROOT.adm directory instead of a CVSROOT
directory, you need to rename it.
Fri Oct 21 20:58:54 1994 Brian Berliner <berliner@sun.com>
* Changes between CVS 1.3 and CVS 1.4 Alpha-2
* A new program, "cvsbug", is provided to let you send bug reports
directly to the CVS maintainers. Please use it instead of sending
mail to the info-cvs mailing list. If your build fails, you may
have to invoke "cvsbug" directly from the "src" directory as
"src/cvsbug.sh".
* A new User's Guide and Tutorial, written by Per Cederqvist
<ceder@signum.se> of Signum Support. See the "doc" directory. A
PostScript version is included as "doc/cvs.ps".
* The Frequesntly Asked Questions file, FAQ, has been added to the
release. Unfortunately, its contents are likely out-of-date.
* The "cvsinit" shell script is now installed in the $prefix/bin
directory like the other programs. You can now create new
CVS repositories with great ease.
* Index: lines are now printed on output from 'diff' and 'rdiff',
in order to facilitate application of patches to multiple subdirs.
* Support for a ~/.cvsrc file, which allows you to specify options
that are always supposed to be given to a specific command. This
feature shows the non-orthogonality of the option set, since while
there may be an option to turn something on, the option to turn
that same thing off may not exist.
* You can now list subdirectories that you wish to ignore in a
modules listing, such as:
gcc -a gnu/gcc, !gnu/gcc/testsuites
which will check out everything underneath gnu/gcc, except
everything underneath gnu/gcc/testsuites.
* It is now much harder to accidentally overwrite an existing tag
name, since attempting to move a tag name will result in a error,
unless the -F (force) flag is given to the tag subcommands.
* Better error checking on matching of the repository used to
check code out from against the repository the current cvs
commnands would use. (Thanks to Mark Baushke <mdb@cisco.com>)
* Better support for sites with multiple CVSROOT repositories has
been contributed. The file "CVS/Root" in your working directory
is created to hold the full path to the CVS repository and a
simple check is made against your current CVSROOT setting.
* You can now specify an RCS keyword substitution value when you
import files into the repository.
* Uses a much newer version of Autoconf, and conforms to the GNU
coding standards much more closely. No, it still doesn't have
long option names.
* Code cleanup. Many passes through gcc -Wall helped to identify
a number of questionable constructs. Most arbitrary length limits
were removed.
* Profiling to determine bottlenecks helped to identify the best
places to spend time speeding up the code, which was then done. A
number of performance enhancements in filename matching have sped
up checkouts.
* Many more contributions have been added to the "contrib"
directory. See the README file in that directory for more
information.
* "cvs commit" will try harder to not change the file's
modification time after the commit. If the file does not change
as a result of the commit operation, CVS will preserve the
original modification time, thus speeding up future make-type
builds.
* "cvs commit" now includes any removed files in the (optional)
pre-commit checking program that may be invoked. Previously, only
added and modified files were included.
* It is now possible to commit a file directly onto the trunk at a
specific revision level by doing "cvs commit -r3.0 file.c", where
"3.0" specifies the revision you wish to create. The file must be
up-to-date with the current head of the trunk for this to succeed.
* "cvs commit" will now function with a pre-commit program that
has arguments specified in the "commitinfo" file.
* The "mkmodules" program will now look within the
$CVSROOT/CVSROOT/checkoutlist" file for any additional files that
should be automatically checked out within CVSROOT; mkmodules also
tries harder to preserve any execute bits the files may have
originally had.
* "cvs diff" is much more accurate about its exit status now. It
now returns the maximum exit status of any invoked diff.
* The "-I !" option is now supported for the import and update
commands correctly. It will properly clear the ignore list now.
* Some problems with "cvs import" handling of .cvsignore have been
fixed; as well, some rampant recursion problems with import have
also been fixed.
* "cvs rdiff" (aka "cvs patch") now tries to set the modify time
of any temporary files it uses to match those specified for the
particular revision. This allows a more accurate patch image to
be created.
* "cvs status" has improved revision descriptions. "Working
revision" is used for the revision of the working file that you
edit directly; "Repository revision" is the revision of the file
with the $CVSROOT source repository. Also, the output is clearer
with regard to sticky and branch revisions.
* CVS no longer dumps core when given a mixture of directories and
files in sub-directories (as in "cvs ci file1 dir1/file2").
Instead, arguments are now clumped into their respective directory
and operated on in chunks, together.
* If the CVSEDITOR environment variable is set, that editor is
used for log messages instead of the EDITOR environment variable.
This makes it easy to substitute intelligent programs to make more
elaborate log messages. Contributed by Mark D Baushke
(mdb@cisco.com).
* Command argument changes:
cvs: The "-f" option has been added to ignore
the ~/.cvsrc file.
commit: Renamed the "-f logfile" option to the
"-F logfile" option. Added the "-f"
option to force a commit of the specified
files (this disables recursion).
history: Added "-t timezone" option to force any
date-specific output into the specified
timezone.
import: Added "-d" option to use the file's
modification time as the time of the
import. Added "-k sub" option to set the
default RCS keyword substitution mode for
newly-created files.
remove: Added "-f" option to force the file's
automatic removal if it still exists in
the working directory (use with caution).
rtag: Added "-F" option to move the tag if it
already exists -- new default is to NOT
move tags automatically.
tag: Added "-F" option to move the tag if it
already exists -- new default is to NOT
move tags automatically.
Tue Apr 7 15:55:25 1992 Brian Berliner (berliner at sun.com)
* Changes between CVS 1.3 Beta-3 and official CVS 1.3!
* A new shell script is provided, "./cvsinit", which can be run at
install time to help setup your $CVSROOT area. This can greatly
ease your entry into CVS usage.
* The INSTALL file has been updated to include the machines on
which CVS has compiled successfully. I think CVS 1.3 is finally
portable. Thanks to all the Beta testers!
* Support for the "editinfo" file was contributed. This file
(located in $CVSROOT/CVSROOT) can be used to specify a special
"editor" to run on a per-directory basis within the repository,
instead of the usual user's editor. As such, it can verify that
the log message entered by the user is of the appropriate form
(contains a bugid and test validation, for example).
* The manual pages cvs(1) and cvs(5) have been updated.
* The "mkmodules" command now informs you when your modules file
has duplicate entries.
* The "add" command now preserves any per-directory sticky tag when
you add a new directory to your checked-out sources.
* The "admin" command is now a fully recursive interface to the
"rcs" program which operates on your checked-out sources. It no
longer requires you to specify the full path to the RCS file.
* The per-file sticky tags can now be effectively removed with
"cvs update -A file", even if you had checked out the whole
directory with a per-directory sticky tag. This allows a great
deal of flexibility in managing the revisions that your checked-out
sources are based upon (both per-directory and per-file sticky
tags).
* The "cvs -n commit" command now works, to show which files are
out-of-date and will cause the real commit to fail, or which files
will fail any pre-commit checks. Also, the "cvs -n import ..."
command will now show you what it would've done without actually
doing it.
* Doing "cvs commit modules" to checkin the modules file will no
properly run the "mkmodules" program (assuming you have setup your
$CVSROOT/CVSROOT/modules file to do so).
* The -t option in the modules file (which specifies a program to
run when you do a "cvs rtag" operation on a module) now gets the
symbolic tag as the second argument when invoked.
* When the source repository is locked by another user, that user's
login name will be displayed as the holder of the lock.
* Doing "cvs checkout module/file.c" now works even if
module/file.c is in the Attic (has been removed from main-line
development).
* Doing "cvs commit */Makefile" now works as one would expect.
Rather than trying to commit everything recursively, it will now
commit just the files specified.
* The "cvs remove" command is now fully recursive. To schedule a
file for removal, all you have to do is "rm file" and "cvs rm".
With no arguments, "cvs rm" will schedule all files that have been
physically removed for removal from the source repository at the
next "cvs commit".
* The "cvs tag" command now prints "T file" for each file that was
tagged by this invocation and "D file" for each file that had the
tag removed (as with "cvs tag -d").
* The -a option has been added to "cvs rtag" to force it to clean
up any old, matching tags for files that have been removed (in the
Attic) that may not have been touched by this tag operation. This
can help keep a consistent view with your tag, even if you re-use
it frequently.
Sat Feb 29 16:02:05 1992 Brian Berliner (berliner at sun.com)
* Changes between CVS 1.3 Beta-2 and CVS 1.3 Beta-3
* Many portability fixes, thanks to all the Beta testers! With any
luck, this Beta release will compile correctly on most anything.
Hey, what are we without our dreams.
* CVS finally has support for doing isolated development on a
branch off the current (or previous!) revisions. This is also
extremely nice for generating patches for previously released
software while development is progressing on the next release.
Here's an example of creating a branch to fix a patch with the 2.0
version of the "foo" module, even though we are already well into
the 3.0 release. Do:
% cvs rtag -b -rFOO_2_0 FOO_2_0_Patch foo
% cvs checkout -rFOO_2_0_Patch foo
% cd foo
[[ hack away ]]
% cvs commit
A physical branch will be created in the RCS file only when you
actually commit the change. As such, forking development at some
random point in time is extremely light-weight -- requiring just a
symbolic tag in each file until a commit is done. To fork
development at the currently checked out sources, do:
% cvs tag -b Personal_Hack
% cvs update -rPersonal_Hack
[[ hack away ]]
% cvs commit
Now, if you decide you want the changes made in the Personal_Hack
branch to be merged in with other changes made in the main-line
development, you could do:
% cvs commit # to make Personal_Hack complete
% cvs update -A # to update sources to main-line
% cvs update -jPersonal_Hack # to merge Personal_Hack
to update your checked-out sources, or:
% cvs checkout -jPersonal_Hack module
to checkout a fresh copy.
To support this notion of forked development, CVS reserves
all even-numbered branches for its own use. In addition, CVS
reserves the ".0" and ".1" branches. So, if you intend to do your
own branches by hand with RCS, you should use odd-numbered branches
starting with ".3", as in "1.1.3", "1.1.5", 1.2.9", ....
* The "cvs commit" command now supports a fully functional -r
option, allowing you to commit your changes to a specific numeric
revision or symbolic tag with full consistency checks. Numeric
tags are useful for bringing your sources all up to some revision
level:
% cvs commit -r2.0
For symbolic tags, you can only commit to a tag that references a
branch in the RCS file. One created by "cvs rtag -b" or from
"cvs tag -b" is appropriate (see below).
* Roland Pesch <pesch@cygnus.com> and K. Richard Pixley
<rich@cygnus.com> were kind enough to contribute two new manual
pages for CVS: cvs(1) and cvs(5). Most of the new CVS 1.3 features
are now documented, with the exception of the new branch support
added to commit/rtag/tag/checkout/update.
* The -j options of checkout/update have been added. The "cvs join"
command has been removed.
With one -j option, CVS will merge the changes made between the
resulting revision and the revision that it is based on (e.g., if
the tag refers to a branch, CVS will merge all changes made in
that branch into your working file).
With two -j options, CVS will merge in the changes between the two
respective revisions. This can be used to "remove" a certain delta
from your working file. E.g., If the file foo.c is based on
revision 1.6 and I want to remove the changes made between 1.3 and
1.5, I might do:
% cvs update -j1.5 -j1.3 foo.c # note the order...
In addition, each -j option can contain on optional date
specification which, when used with branches, can limit the chosen
revision to one within a specific date. An optional date is
specified by adding a colon (:) to the tag, as in:
-jSymbolic_Tag:Date_Specifier
An example might be what "cvs import" tells you to do when you have
just imported sources that have conflicts with local changes:
% cvs checkout -jTAG:yesterday -jTAG module
which tells CVS to merge in the changes made to the branch
specified by TAG in the last 24 hours. If this is not what is
intended, substitute "yesterday" for whatever format of date that
is appropriate, like:
% cvs checkout -jTAG:'1 week ago' -jTAG module
* "cvs diff" now supports the special tags "BASE" and "HEAD". So,
the command:
% cvs diff -u -rBASE -rHEAD
will effectively show the changes made by others (in unidiff
format) that will be merged into your working sources with your
next "cvs update" command. "-rBASE" resolves to the revision that
your working file is based on. "-rHEAD" resolves to the current
head of the branch or trunk that you are working on.
* The -P option of "cvs checkout" now means to Prune empty
directories, as with "update". The default is to not remove empty
directories. However, if you do "checkout" with any -r options, -P
will be implied. I.e., checking out with a tag will cause empty
directories to be pruned automatically.
* The new file INSTALL describes how to install CVS, including
detailed descriptions of interfaces to "configure".
* The example loginfo file in examples/loginfo has been updated to
use the perl script included in contrib/log.pl. The nice thing
about this log program is that it records the revision numbers of
your change in the log message.
Example files for commitinfo and rcsinfo are now included in the
examples directory.
* All "#if defined(__STDC__) && __STDC__ == 1" lines have been
changed to be "#if __STDC__" to fix some problems with the former.
* The lib/regex.[ch] files have been updated to the 1.3 release of
the GNU regex package.
* The ndbm emulation routines included with CVS 1.3 Beta-2 in the
src/ndbm.[ch] files has been moved into the src/myndbm.[ch] files
to avoid any conflict with the system <ndbm.h> header file. If
you had a previous CVS 1.3 Beta release, you will want to "cvs
remove ndbm.[ch]" form your copy of CVS as well.
* "cvs add" and "cvs remove" are a bit more verbose, telling you
what to do to add/remove your file permanently.
* We no longer mess with /dev/tty in "commit" and "add".
* More things are quiet with the -Q option set.
* New src/config.h option: If CVS_BADROOT is set, CVS will not
allow people really logged in as "root" to commit changes.
* "cvs diff" exits with a status of 0 if there were no diffs, 1 if
there were diffs, and 2 if there were errors.
* "cvs -n diff" is now supported so that you can still run diffs
even while in the middle of committing files.
* Handling of the CVS/Entries file is now much more robust.
* The default file ignore list now includes "*.so".
* "cvs import" did not expand '@' in the log message correctly. It
does now. Also, import now uses the ignore file facility
correctly.
Import will now tell you whether there were conflicts that need to
be resolved, and how to resolve them.
* "cvs log" has been changed so that you can "log" things that are
not a part of the current release (in the Attic).
* If you don't change the editor message on commit, CVS now prompts
you with the choice:
!)reuse this message unchanged for remaining dirs
which allows you to tell CVS that you have no intention of changing
the log message for the remainder of the commit.
* It is no longer necessary to have CVSROOT set if you are using
the -H option to get Usage information on the commands.
* Command argument changes:
checkout: -P handling changed as described above.
New -j option (up to 2 can be specified)
for doing rcsmerge kind of things on
checkout.
commit: -r option now supports committing to a
numeric or symbolic tags, with some
restrictions. Full consistency checks will
be done.
Added "-f logfile" option, which tells
commit to glean the log message from the
specified file, rather than invoking the
editor.
rtag: Added -b option to create a branch tag,
useful for creating a patch for a previous
release, or for forking development.
tag: Added -b option to create a branch tag,
useful for creating a patch for a previous
release, or for forking development.
update: New -j option (up to 2 can be specified)
for doing rcsmerge kind of things on
update.
Thu Jan 9 10:51:35 MST 1992 Jeff Polk (polk at BSDI.COM)
* Changes between CVS 1.3 Beta-1 and CVS 1.3 Beta-2
* Thanks to K. Richard Pixley at Cygnus we now have function
prototypes in all the files
* Some small changes to configure for portability. There have
been other portability problems submitted that have not been fixed
(Brian will be working on those). Additionally all __STDC__
tests have been modified to check __STDC__ against the constant 1
(this is what the Second edition of K&R says must be true).
* Lots of additional error checking for forked processes (run_exec)
(thanks again to K. Richard Pixley)
* Lots of miscellaneous bug fixes - including but certainly not
limited to:
various commit core dumps
various update core dumps
bogus results from status with numeric sticky tags
commitprog used freed memory
Entries file corruption caused by No_Difference
commit to revision broken (now works if branch exists)
ignore file processing broken for * and !
ignore processing didn't handle memory reasonably
miscellaneous bugs in the recursion processor
file descriptor leak in ParseInfo
CVSROOT.adm->CVSROOT rename bug
lots of lint fixes
* Reformatted all the code in src (with GNU indent) and then
went back and fixed prototypes, etc since indent gets confused. The
rationale is that it is better to do it sooner than later and now
everything is consistent and will hopefully stay that way.
The basic options to indent were: "-bad -bbb -bap -cdb -d0 -bl -bli0
-nce -pcs -cs -cli4 -di1 -nbc -psl -lp -i4 -ip4 -c41" and then
miscellaneous formatting fixes were applied. Note also that the
"-nfc1" or "-nfca" may be appropriate in files where comments have
been carefully formatted (e.g, modules.c).
Sat Dec 14 20:35:22 1991 Brian Berliner (berliner at sun.com)
* Changes between CVS 1.2 and CVS 1.3 Beta are described here.
* Lots of portability work. CVS now uses the GNU "configure"
script to dynamically determine the features provided by your
system. It probably is not foolproof, but it is better than
nothing. Please let me know of any portability problems. Some
file names were changed to fit within 14-characters.
* CVS has a new RCS parser that is much more flexible and
extensible. It should read all known RCS ",v" format files.
* Most of the commands now are fully recursive, rather than just
operating on the current directory alone. This includes "commit",
which makes it real easy to do an "atomic" commit of all the
changes made to a CVS hierarchy of sources. Most of the commands
also correctly handle file names that are in directories other than
".", including absolute path names. Commands now accept the "-R"
option to force recursion on (though it is always the default now)
and the "-l" option to force recursion off, doing just "." and not
any sub-directories.
* CVS supports many of the features provided with the RCS 5.x
distribution - including the new "-k" keyword expansion options. I
recommend using RCS 5.x (5.6 is the current official RCS version)
and GNU diff 1.15 (or later) distributions with CVS.
* Checking out files with symbolic tags/dates is now "sticky", in
that CVS remembers the tag/date used for each file (and directory)
and will use that tag/date automatically on the next "update" call.
This stickyness also holds for files checked out with the the new
RCS 5.x "-k" options.
* The "cvs diff" command now recognizes all of the rcsdiff 5.x
options. Unidiff format is available by installing the GNU
diff 1.15 distribution.
* The old "CVS.adm" directories created on checkout are now called
"CVS" directories, to look more like "RCS" and "SCCS". Old CVS.adm
directories are automagically converted to CVS directories. The
old "CVSROOT.adm" directory within the source repository is
automagically changed into a "CVSROOT" directory as well.
* Symbolic links in the source repository are fully supported ONLY
if you use RCS 5.6 or later and (of course) your system supports
symlinks.
* A history database has been contributed which maintains the
history of certain CVS operations, as well as providing a wide array
of querying options.
* The "cvs" program has a "-n" option which can be used with the
"update" command to show what would be updated without actually
doing the update, like: "cvs -n update". All usage statements
have been cleaned up and made more verbose.
* The module database parsing has been rewritten. The new format
is compatible with the old format, but with much more
functionality. It allows modules to be created that grab pieces or
whole directories from various different parts of your source
repository. Module-relative specifications are also correctly
recognized now, like "cvs checkout module/file.c".
* A configurable template can be specified such that on a "commit",
certain directories can supply a template that the user must fill
before completing the commit operation.
* A configurable pre-commit checking program can be specified which
will run to verify that a "commit" can happen. This feature can be
used to restrict certain users from changing certain pieces of the
source repository, or denying commits to the entire source
repository.
* The new "cvs export" command is much like "checkout", but
establishes defaults suitable for exporting code to others (expands
out keywords, forces the use of a symbolic tag, and does not create
"CVS" directories within the checked out sources.
* The new "cvs import" command replaces the deprecated "checkin"
shell script and is used to import sources into CVS control. It is
also much faster for the first-time import. Some algorithmic
improvements have also been made to reduce the number of
conflicting files on next-time imports.
* The new "cvs admin" command is basically an interface to the
"rcs" program. (Not yet implemented very well).
* Signal handling (on systems with BSD or POSIX signals) is much
improved. Interrupting CVS now works with a single interrupt!
* CVS now invokes RCS commands by direct fork/exec rather than
calling system(3). This improves performance by removing a call to
the shell to parse the arguments.
* Support for the .cvsignore file has been contributed. CVS will
now show "unknown" files as "? filename" as the result of an "update"
command. The .cvsignore file can be used to add files to the
current list of ignored files so that they won't show up as unknown.
* Command argument changes:
cvs: Added -l to turn off history logging.
Added -n to show what would be done without actually
doing anything.
Added -q/-Q for quiet and really quiet settings.
Added -t to show debugging trace.
add: Added -k to allow RCS 5.x -k options to be specified.
admin: New command; an interface to rcs(1).
checkout: Added -A to reset sticky tags/date/options.
Added -N to not shorten module paths.
Added -R option to force recursion.
Changed -p (prune empty directories) to -P option.
Changed -f option; forcing tags match is now default.
Added -p option to checkout module to standard output.
Added -s option to cat the modules db with status.
Added -d option to checkout in the specified directory.
Added -k option to use RCS 5.x -k support.
commit: Removed -a option; use -l instead.
Removed -f option.
Added -l option to disable recursion.
Added -R option to force recursion.
If no files specified, commit is recursive.
diff: Now recognizes all RCS 5.x rcsdiff options.
Added -l option to disable recursion.
Added -R option to force recursion.
history: New command; displays info about CVS usage.
import: Replaces "checkin" shell script; imports sources
under CVS control. Ignores files on the ignore
list (see -I option or .cvsignore description above).
export: New command; like "checkout", but w/special options
turned on by default to facilitate exporting sources.
join: Added -B option to join from base of the branch;
join now defaults to only joining with the top two
revisions on the branch.
Added -k option for RCS 5.x -k support.
log: Supports all RCS 5.x options.
Added -l option to disable recursion.
Added -R option to force recursion.
patch: Changed -f option; forcing tags match is now default.
Added -c option to force context-style diffs.
Added -u option to support unidiff-style diffs.
Added -V option to support RCS specific-version
keyword expansion formats.
Added -R option to force recursion.
remove: No option changes. It's a bit more verbose.
rtag: Equivalent to the old "cvs tag" command.
No option changes. It's a lot faster for re-tag.
status: New output formats with more information.
Added -l option to disable recursion.
Added -R option to force recursion.
Added -v option to show symbolic tags for files.
tag: Functionality changed to tag checked out files
rather than modules; use "rtag" command to get the
old "cvs tag" behaviour.
update: Added -A to reset sticky tags/date/options.
Changed -p (prune empty directories) to -P option.
Changed -f option; forcing tags match is now default.
Added -p option to checkout module to standard output.
Added -I option to add files to the ignore list.
Added -R option to force recursion.
Major Contributors:
* Jeff Polk <polk@bsdi.com> rewrote most of the grody code of CVS
1.2. He made just about everything dynamic (by using malloc),
added a generic hashed list manager, re-wrote the modules database
parsing in a compatible - but extended way, generalized directory
hierarchy recursion for virtually all the commands (including
commit!), generalized the loginfo file to be used for pre-commit
checks and commit templates, wrote a new and flexible RCS parser,
fixed an uncountable number of bugs, and helped in the design of
future CVS features. If there's anything gross left in CVS, it's
probably my fault!
* David G. Grubbs <dgg@odi.com> contributed the CVS "history" and
"release" commands. As well as the ever-so-useful "-n" option of
CVS which tells CVS to show what it would do, without actually
doing it. He also contributed support for the .cvsignore file.
* Paul Sander, HaL Computer Systems, Inc. <paul@hal.com> wrote and
contributed the code in lib/sighandle.c. I added support for
POSIX, BSD, and non-POSIX/non-BSD systems.
* Free Software Foundation contributed the "configure" script and
other compatibility support in the "lib" directory, which will help
make CVS much more portable.
* Many others have contributed bug reports and enhancement requests.
Some have even submitted actual code which I have not had time yet
to integrate into CVS. Maybe for the next release.
* Thanks to you all!
Wed Feb 6 10:10:58 1991 Brian Berliner (berliner at sun.com)
* Changes from CVS 1.0 Patchlevel 1 to CVS 1.0 Patchlevel 2; also
known as "Changes from CVS 1.1 to CVS 1.2".
* Major new support with this release is the ability to use the
recently-posted RCS 5.5 distribution with CVS 1.2. See below for
other assorted bug-fixes that have been thrown in.
* ChangeLog (new): Added Emacs-style change-log file to CVS 1.2
release. Chronological description of changes between release.
* README: Small fixes to installation instructions. My email
address is now "berliner@sun.com".
* src/Makefile: Removed "rcstime.h". Removed "depend" rule.
* src/partime.c: Updated to RCS 5.5 version with hooks for CVS.
* src/maketime.c: Updated to RCS 5.5 version with hooks for CVS.
* src/rcstime.h: Removed from the CVS 1.2 distribution.
Thanks to Paul Eggert <eggert@twinsun.com> for these changes.
* src/checkin.csh: Support for RCS 5.5 parsing.
Thanks to Paul Eggert <eggert@twinsun.com> for this change.
* src/collect_sets.c (Collect_Sets): Be quieter if "-f" option is
specified. When checking out files on-top-of other files that CVS
doesn't know about, run a diff in the hopes that they are really
the same file before aborting.
* src/commit.c (branch_number): Fix for RCS 5.5 parsing.
Thanks to Paul Eggert <eggert@twinsun.com> for this change.
* src/commit.c (do_editor): Bug fix - fprintf missing argument
which sometimes caused core dumps.
* src/modules.c (process_module): Properly NULL-terminate
update_dir[] in all cases.
* src/no_difference.c (No_Difference): The wrong RCS revision was
being registered in certain (strange) cases.
* src/patch.c (get_rcsdate): New algorithm. No need to call
maketime() any longer.
Thanks to Paul Eggert <eggert@twinsun.com> for this change.
* src/patchlevel.h: Increased patch level to "2".
* src/subr.c (isdir, islink): Changed to compare stat mode bits
correctly.
* src/tag.c (tag_file): Added support for following symbolic links
that are in the master source repository when tagging. Made tag
somewhat quieter in certain cases.
* src/update.c (update_process_lists): Unlink the user's file if it
was put on the Wlist, meaning that the user's file is not modified
and its RCS file has been removed by someone else.
* src/update.c (update): Support for "cvs update dir" to correctly
just update the argument directory "dir".
* src/cvs.h: Fixes for RCS 5.5 parsing.
* src/version_number.c (Version_Number): Fixes for parsing RCS 5.5
and older RCS-format files.
Thanks to Paul Eggert <eggert@twinsun.com> for these changes.
* src/version_number.c (Version_Number): Bug fixes for "-f" option.
Bug fixes for parsing with certain branch numbers. RCS
revision/symbol parsing is much more solid now.
Wed Feb 14 10:01:33 1990 Brian Berliner (berliner at sun.com)
* Changes from CVS 1.0 Patchlevel 0 to CVS 1.0 Patchlevel 1; also
known as "Changes from CVS 1.0 to CVS 1.1".
* src/patch.c (get_rcsdate): Portability fix. Replaced call to
timelocal() with call to maketime().
Mon Nov 19 23:15:11 1990 Brian Berliner (berliner at prisma.com)
* Sent CVS 1.0 release to comp.sources.unix moderator and FSF.
* Special thanks to Dick Grune <dick@cs.vu.nl> for his work on the
1986 version of CVS and making it available to the world. Dick's
version is available on uunet.uu.net in the
comp.sources.unix/volume6/cvs directory.
$CVSid: @(#)ChangeLog 1.35 94/10/22 $

View file

@ -1,59 +0,0 @@
This is a list of projects for CVS. In general, unlike the things in
the TODO file, these need more analysis to determine if and how
worthwhile each task is.
I haven't gone through TODO, but it's likely that it has entries that
are actually more appropriate for this list.
0. Improved Efficency
* CVS uses a single doubly linked list/hash table data structure for
all of its lists. Since the back links are only used for deleting
list nodes it might be beneficial to use singly linked lists or a
tree structure. Most likely, a single list implementation will not
be appropriate for all uses.
One easy change would be to remove the "type" field out of the list
and node structures. I have found it to be of very little use when
debugging, and each instance eats up a word of memory. This can add
up and be a problem on memory-starved machines.
Profiles have shown that on fast machines like the Alpha, fsortcmp()
is one of the hot spots.
* Dynamically allocated character strings are created, copied, and
destroyed throughout CVS. The overhead of malloc()/strcpy()/free()
needs to be measured. If significant, it could be minimized by using a
reference counted string "class".
* File modification time is stored as a character string. It might be
worthwile to use a time_t internally if the time to convert a time_t
(from struct stat) to a string is greater that the time to convert a
ctime style string (from the entries file) to a time_t. time_t is
an machine-dependant type (although it's pretty standard on UN*X
systems), so we would have to have different conversion routines.
Profiles show that both operations are called about the same number
of times.
* stat() is one of the largest performance bottlenecks on systems
without the 4.4BSD filesystem. By spliting information out of
the filesystem (perhaps the "rename database") we should be
able to improve performance.
* Parsing RCS files is very expensive. This might be unnecessary if
RCS files are only used as containers for revisions, and tag,
revision, and date information was available in easy to read
(and modify) indexes. This becomes very apparent with files
with several hundred revisions.
* A RCS "library", so CVS could operate on RCS files directly.
CVS parses RCS files in order to determine if work needs to be done,
and then RCS parses the files again when it is performing the work.
This would be much faster if CVS could do whatever is necessary
by itself.
1. Improved testsuite/sanity check script
* Need to use a code coverage tool to determine how much the sanity
script tests, and fill in the holes.

View file

@ -1,207 +0,0 @@
$CVSid: @(#)README 1.32 94/10/22 $
CVS Kit
Copyright (c) 1993-1994 Brian Berliner
Copyright (c) 1992 Brian Berliner and Jeff Polk
Copyright (c) 1989-1992, Brian Berliner
All Rights Reserved
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 1, 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.
-------------------------------------------------------------------------------
Welcome to CVS!
Bug reports are accepted, however note that someone may or may not
feel like taking care of your bug report. Support contracts are
available from Cyclic Software (http://www.cyclic.com).
To report bugs send mail to bug-cvs@prep.ai.mit.edu, or run the "cvsbug"
program and fill out the template:
$ cvsbug
The "cvsbug" program is installed in the same location as the "cvs"
program. If your installation failed, you may need to run "cvsbug"
directly out of the "src" directory as "src/cvsbug.sh".
Please consult the INSTALL file for information on tested
configurations. If you have a comment about an already tested
configuration, or have tried CVS on a new configuration, please write
to the above address and let us know! Free software only works if we
all help out.
Finally, we cannot guarantee that this release will not completely wipe out
all of your work from your system. We do some simple testing before each
release, but you are completely on your own. We recommend testing this
release on a source repository that is not critical to your work. THIS
SOFTWARE IS SUPPLIED COMPLETELY "AS IS". NO WARRANTY....
Thanks for your support!
-The CVS Team, and the Cyclic CVS Hackers
-------------------------------------------------------------------------------
CVS is a freely available collection of programs that provide for software
release and revision control functions in a UNIX environment. It is
designed to work on top of the RCS distribution, V4 and later. CVS does
understand how to parse older RCS formats, but cannot do any of the fancier
features (like vendor branch support) without RCS branch support.
Short blurb from the manual page (larger blurb is included there):
cvs is a front end to the rcs(1) revision control system
which extends the notion of revision control from a collec-
tion of files in a single directory to a hierarchical col-
lection of directories consisting of revision controlled
files. These directories and files can be combined together
to form a software release. cvs provides the functions
necessary to manage these software releases and to control
the concurrent editing of source files among multiple
software developers.
And a whole lot more. See the man/cvs.1 file for more information.
-------------------------------------------------------------------------------
Special note to current CVS 1.3 users:
--> You can skip this section and go straight to "Installation" if you <--
--> have not been running any previous releases of CVS. <--
See the NEWS file for a description of features new in this version.
Some files have been renamed from the CVS 1.3 distribution. If you're
not careful, this can cause your CVS build to fail in strange ways.
In particular, be sure to remove the src/config.h file (which is now
src/options.h), as the correct config.h file is generated
automatically by the "configure" stage of installation (and installed
in this directory).
-------------------------------------------------------------------------------
Installation:
Please read the INSTALL file for installation instructions. Brief summary:
$ ./configure
$ make
$ make check # optional, long-running, step
$ make install
$ cvsinit
-------------------------------------------------------------------------------
* How do I get up-to-date information and information about other
versions of CVS?
On the web, http://www.winternet.com/~zoo/cvs/ or
http://www.loria.fr/~molli/cvs-index.html.
The mailing list for CVS is info-cvs@prep.ai.mit.edu. Send
subscription and removal requests for that list to
info-cvs-requests@prep.ai.mit.edu.
[Historical note: info-cvs@prep.ai.mit.edu is now the union of
info-cvs@prep and cyclic-cvs@cyclic.com. Please use the prep
address.]
-------------------------------------------------------------------------------
Credits:
The conflict-resolution algorithms and much of the administrative file
definitions of CVS were based on the original package written by Dick Grune
at Vrije Universiteit in Amsterdam <dick@cs.vu.nl>, and posted to
comp.sources.unix in the volume 6 release sometime in 1986. This original
version was a collection of shell scripts. I am thankful that Dick made
his work available.
Brian Berliner from Prisma, Inc. (now at Sun Microsystems, Inc.)
<berliner@sun.com> converted the original CVS shell scripts into reasonably
fast C and added many, many features to support software release control
functions. See the manual page in the "man" directory. A copy of the
USENIX article presented at the Winter 1990 USENIX Conference, Washington
D.C., is included in the "doc" directory.
Jeff Polk from BSDI <polk@bsdi.com> converted the CVS 1.2
sources into much more readable and maintainable C code. He also added a
whole lot of functionality and modularity to the code in the process.
See the ChangeLog file.
david d `zoo' zuhn <zoo@armadillo.com> contributed the working base code
for CVS 1.4 Alpha. His work carries on from work done by K. Richard Pixley
and others at Cygnus Support. The CVS 1.4 upgrade is due in large part to
Zoo's efforts.
David G. Grubbs <dgg@odi.com> contributed the CVS "history" and "release"
commands. As well as the ever-so-useful "-n" option of CVS which tells CVS
to show what it would do, without actually doing it. He also contributed
support for the .cvsignore file.
The Free Software Foundation (GNU) contributed most of the portability
framework that CVS now uses. This can be found in the "configure" script,
the Makefile's, and basically most of the "lib" directory.
K. Richard Pixley, Cygnus Support <rich@cygnus.com> contributed many bug
fixes/enhancement as well as completing early reviews of the CVS 1.3 manual
pages.
Roland Pesch, then of Cygnus Support <roland@wrs.com> contributed brand new
cvs(1) and cvs(5) manual pages. We should all thank him for saving us from
my poor use of our language!
Paul Sander, HaL Computer Systems, Inc. <paul@hal.com> wrote and
contributed the code in lib/sighandle.c. I added support for POSIX, BSD,
and non-POSIX/non-BSD systems.
Jim Kingdon and others at Cygnus Support <info@cygnus.com> wrote the
remote repository access code.
In addition to the above contributors, the following Beta testers deserve
special mention for their support. If I have left off your name, I
apologize. Just write to me and let me know!
Mark D. Baushke <mdb@cisco.com>
Per Cederqvist <ceder@signum.se>
J.T. Conklin (jtc@cygnus.com>
Vince DeMarco <vdemarco@fdcsrvr.cs.mci.com>
Paul Eggert <eggert@twinsun.com>
Lal George <george@research.att.com>
Dean E. Hardi <Dean.E.Hardi@ccmail.jpl.nasa.gov>
Mike Heath <mike@pencom.com>
Jim Kingdon <kingdon@cygnus.com>
Bernd Leibing <bernd.leibing@rz.uni-ulm.de>
Benedict Lofstedt <benedict@tusc.com.au>
Dave Love <d.love@dl.ac.uk>
Robert Lupton the Good <rhl@astro.princeton.edu>
Tom McAliney <tom@hilco.com>
Eberhard Mattes <mattes@azu.informatik.uni-stuttgart.de>
Jim Meyering <meyering@comco.com>
Thomas Mohr <mohr@lts.sel.alcatel.de>
Thomas Nilsson <thoni@softlab.se>
Raye Raskin <raye.raskin@lia.com>
Harlan Stenn <harlan@landmark.com>
Gunnar Tornblom <gunnar.tornblom@senet.abb.se>
Greg A. Woods <woods@kuma.web.net>
Many contributors have added code to the "contrib" directory. See the
README file there for a list of what is available. There is also a
contributed GNU Emacs CVS-mode in contrib/pcl-cvs.
-------------------------------------------------------------------------------
Cyclic Software <info@cyclic.com>

View file

@ -1,474 +0,0 @@
$CVSid: @(#)TODO 1.26 94/09/21 $
14. Pathname stripper, for checkout, as well as for writing the
Repository file.
[[ I have a simple one, but need to make sure to call it at all the
appropriate points ]]
(I'm not sure what this means -kingdon, Jun 1995).
16. List of current users of a directory needs to be maintained.
[[ sort of solved by history database ]]
22. Catch signals for cleanup when "add"ing files.
24. Insist on a log message.
(This should be configurable via commitinfo or some new config file
-kingdon, Jun 1995).
30. Add "patch" program option to the modules database.
31. Think hard about ^C recovery.
35. Add "admin" command as an interface to "rcs".
[[ a cheesy version is there, but it should be re-done ]]
38. Think hard about using RCS state information to allow one to checkin
a new vendor release without having it be accessed until it has been
integrated into the local changes.
39. Think about allowing parallel source trees that can easily track
each other.
[[ sort of solved with the automagic branch support, but I want more ]]
45. Consider enhancing the "patch" and "tag" command support in the module
database -- they seem hard to use since these commands deal directly
with the RCS ,v files.
46. Perhaps checkout/checkin/tag/patch commands should be imbedded in the
file system directly, using special known command names?
49. cvs xxx commands should be able to deal with files in other
directories. I want to do a cvs add foo/bar.c.
[[ most commands now use the generic recursion processor, but not all;
this note is left here to remind me to fix the others ]]
51. a way to identify what files other people are working on. Imagine "cvs
modified", which prints out a table like
file modifiers
===== =========
foo.c
bar.c wsd
baz.c nrt jda
I think this would be pretty difficult; I don't know if this
information is stored anywhere. Also it's hard to say how one gets a
user name, maybe a path to their local hierarchy is all you could get.
[[ the history stuff does some of this, but not all ]]
52. SCCS has a feature that I would *love* to see in CVS, as it is very
useful. One may make a private copy of SCCS suid to a particular user,
so other users in the authentication list may check files in and out of
a project directory without mucking about with groups. Is there any
plan to provide a similar functionality to CVS? Our site (and, I'd
imagine, many other sites with large user bases) has decided against
having the user-groups feature of unix available to the users, due to
perceived administrative, technical and performance headaches. A tool
such as CVS with features that provide group-like functionality would
be a huge help.
53. I'd suggest a way to notify users if/when a file(s) is being worked on.
I suggest:
+ Always checkout/update files a readonly.
+ To work on a file, the user should do:
cvs advise filename
+ This would maintain their email address associated with that
file name in the repository and change the file mode to writable.
+ If other references to that file exist, the registered individuals
are notified via email that another user(s) is going to be working
on same.
+ When a committ occurs, the user is automatically 'unadvise'd (the
inverse command should be supported as well) and other's are notified
that a merge will be necessary before their checkin can be
successful.
62. Consider using revision controlled files and directories to handle the
new module format -- consider a cvs command front-end to
add/delete/modify module contents, maybe.
63. The "import" and vendor support commands (co -j) need to be documented
better.
64. Need to greatly increase the performance of an initial checkout.
[[ it got better, then we added functionality, making it worse again ]]
66. Length of the CVS temporary files must be limited to 14 characters for
System-V stupid support. As weel as the length on the CVS.adm files.
67. cvs import should populate the vendor sources with CVS.adm files so
that one could use the vendor sources directly without having the check
them out.
69. Consider enhacing import to add a module automatically to the module
database. Perhaps with a new option, or perhaps with an editor.
72. Consider re-design of the module -o, -i, -t options to use the file
system more intuitively.
73. Consider an option (in .cvsrc?) to automatically add files that are new
and specified to commit.
74. Consider adding a way to remove directories/files that you are done
with... somehow.
[[ cvs release sort of does this ]]
76. Consider adding a layer of abstraction so that CVS can work with both
RCS and SCCS files. Larry says this should be #ifdef'ed.
79. Might be nice to have some sort of interface to TFS and tagged
revisions.
82. Maybe the import stuff should allow an arbitrary revision to be
specified.
84. Improve the documentation about administration of the repository and
how to add/remove files and the use of symbolic links.
85. Add revision controlled symbolic links to CVS using one of the tag
fields in the RCS file.
91. Better document the format of the source repository and how one might
convert their current SCCS or RCS files into CVS format.
92. Look into this:
After a bit of soul searching via dbx, I realized my sin was that I'd
specified "echo" as the program to call from loginfo. The commit
procedure worked fine till it hit my echo, then silently aborted
leaving the lockfiles intact. Since I needn't use the loginfo
facility, I simply removed those commands and it all works.
93. Need to think hard about release and development environments. Think
about execsets as well.
98. If diff3 bombs out (too many differences) cvs then thinks that the file
has been updated and is OK to be commited even though the file
has not yet been merged.
100. Checked out files should have revision control support. Maybe.
102. Perhaps directory modes should be propagated on all import check-ins.
Not necessarily uid/gid changes.
103. setuid/setgid on files is suspect.
104. cvs should recover nicely on unreadable files/directories.
105. cvs should have administrative tools to allow for changing permissions
and modes and what not. In particular, this would make cvs a
more attractive alternative to rdist.
107. It should be possible to specify a list of symbolic revisions to
checkout such that the list is processed in reverse order looking for
matches within the RCS file for the symbolic revision. If there is
not a match, the next symbolic rev on the list is checked, and so on,
until all symbolic revs are exhausted. This would allow one to, say,
checkout "4.0" + "4.0.3" + "4.0.3Patch1" + "4.0.3Patch2" to get the
most recent 4.x stuff. This is usually handled by just specifying the
right release_tag, but most people forget to do this.
108. If someone creates a whole new directory (i.e. adds it to the cvs
repository) and you happen to have a directory in your source farm by
the same name, when you do your cvs update -d it SILENTLY does
*nothing* to that directory. At least, I think it was silent;
certainly, it did *not* abort my cvs update, as it would have if the
same thing had happened with a file instead of a directory.
109. I had gotten pieces of the sys directory in the past but not a
complete tree. I just did something like:
cvs get *
Where sys was in * and got the message
cvs get: Executing 'sys/tools/make_links sys'
sh: sys/tools/make_links: not found
I suspect this is because I didn't have the file in question,
but I do not understand how I could fool it into getting an
error. I think a later cvs get sys seemed to work so perhaps
something is amiss in handling multiple arguments to cvs get?
113. The "cvs update" command should tee its output to a log file in ".".
(why? What is wrong with piping stdout to "tee"? -kingdon, Jun 1995)
115. I still think "cvs modules" is a good idea.
Since everything else is inside cvs, "mkmodules" should be in there too:
Add a "modules" (synonym "mod") command directly in cvs.
("checkout -c" is not really intuitive. I'd move it into "mod -s".)
"mod" Print database as typed. (line count as record id?)
"mod -s" Print the sorted database (as "checkout -c" does now)
"mod -m" Internal replacement for "mkmodules" command.
"mod module ..." Print the raw dbm record for the named modules
"mod -p module ..." Print relative filenames contained in modules.(no ",v")
"mod -l module ..." Prints more info about relative filenames ("ls -l"?)
"mod -f file ..." Tells you what module(s) the filenames are in.
119. Consider an option to have import checkout the RCS or SCCS files
if necessary.
122. If Name_Repository fails, it currently causes CVS to die completely. It
should instead return NULL and have the caller do something reasonable.
123. Add a flag to import to not build vendor branches for local code.
124. Anyway, I thought you might want to add something like the following
to the cvs and mkmodules man pages:
BUGS
The sum of the sizes of a module key and its contents are
limited. See ndbm(3).
126. Do an analysis to see if CVS is forgetting to close file descriptors.
Especially when committing many files (more than the open file limit
for the particular UNIX).
127. Look at *info files; they should all be quiet if the files are not
there. Should be able to point at a RCS directory and go.
128. When I tag a file, the message tells me that I'm tagging a directory.
129. Something strange seems to have happened here. When I check this out,
the update lines (U CFTS/...) seem to report a bogus leading CFTS
(e.g. U CFTS/Medusa_TS/...) when the later files are checked out.
The directory structure doesn't seem to be botched, just the
messages. I don't recall seeing this before.
130. cvs diff with no -r arguments does not need to look up the current RCS
version number since it only cares about what's in the Entries file.
This should make it much faster.
It should ParseEntries itself and access the entries list much like
Version_TS does (sticky tags and sticky options may need to be
supported here as well). Then it should only diff the things that
have the wrong time stamp (the ones that look modified).
134. Make a statement about using hard NFS mounts to your source
repository. Look into checking NULL fgets() returns with ferror() to
see if an error had occurred.
135. The email CVS sends with each checkin, should include the version
number of each file it is checking in.
[[ Sort of solved by contrib/log.pl, which does a good job of this ]]
137. Some sites might want CVS to fsync() the RCS ,v file to protect
against nasty hardware errors. There is a slight performance hit with
doing so, though, so it should be configurable in the .cvsrc file.
Also, along with this, we should look at the places where CVS itself
could be a little more synchronous so as not to lose data.
[[ I've done some of this, but it could use much more ]]
138. Some people have suggested that CVS use a VPATH-like environment
variable to limit the amount of sources that need to be duplicated for
sites with giant source trees and no disk space.
141. Import should accept modules as its directory argument.
143. Update the documentation to show that the source repository is
something far away from the files that you work on.
144. Have cvs checkout look for the environment variable CVSPREFIX
(or CVSMODPREFIX or some such). If it's set, then when looking
up an alias in the modules database, first look it up with the
value of CVSPREFIX attached, and then look for the alias itself.
This would be useful when you have several projects in a single
repository. You could have aliases abc_src and xyz_src and
tell people working on project abc to put "setenv CVSPREFIX abc_"
in their .cshrc file (or equivalent for other shells).
Then they could do "cvs co src" to get a copy of their src
directory, not xyz's. (This should create a directory called
src, not abc_src.)
145. After you create revision 1.1.1.1 in the previous scenario, if
you do "cvs update -r1 filename" you get revision 1.1, not
1.1.1.1. It would be nice to get the later revision. Again,
this restriction comes from RCS and is probably hard to
change in CVS. Sigh.
|"cvs update -r1 filename" does not tell RCS to follow any branches. CVS
|tries to be consistent with RCS in this fashion, so I would not change
|this. Within CVS we do have the flexibility of extending things, like
|making a revision of the form "-r1HEAD" find the most recent revision
|(branch or not) with a "1." prefix in the RCS file. This would get what
|you want maybe.
This would be very useful. Though I would prefer an option
such as "-v1" rather than "-r1HEAD". This option might be
used quite often.
146. The merging of files should be controlled via a hook so that programs
other than "rcsmerge" can be used, like Sun's filemerge or emacs's
emerge.el. (but be careful in making this work client/server--it means
doing the interactive merging at the end after the server is done).
149. On Sun, 2 Feb 92 22:01:38 EST, rouilj@dl5000.bc.edu (John P. Rouillard)
said:
Maybe there should be an option to cvs admin that allows a user to
change the Repository file with some degree of error checking?
Something like "cvs admin reposmv /old/path /new/pretty/path". Before
it does the replace it check to see that the files
/new/pretty/path/<dir>/<files> exist.
150. I have a customer request for a way to specify log message per
file, non-interactively before the commit, such that a single, fully
recursive commit prompts for one commit message, and concatenates the
per file messages for each file. In short, one commit, one editor
session, log messages allowed to vary across files within the commit.
Also, the per file messages should be allowed to be written when the
files are changed, which may predate the commit considerably.
A new command seems appropriate for this. The state can be saved in the
CVS directory. I.e.,
% cvs msg foo.c
Enter log message for foo.c
>> fixed an uninitialized variable
>> ^D
The text is saved as CVS/foo.c,m (or some such name) and commit is
modified to append (prepend?) the text (if found) to the log message
specified at commit time. Easy enough.
151. Also, is there a flag I am missing that allows replacing Ulrtx_Build
by Ultrix_build? I.E. I would like a tag replacement to be a one step
operation rather than a two step "cvs rtag -r Ulrtx_Build Ultrix_Build"
followed by "cvs trag -d Ulrtx_Build"
152. The "cvs -n" option does not work as one would expect for all the
commands. In particular, for "commit" and "import", where one would
also like to see what it would do, without actually doing anything.
153. There should be some command (maybe I just haven't figured
out which one...) to import a source directory which is already
RCS-administered without losing all prior RCS gathered data. Thus, it
would have to examine the RCS files and choose a starting version and
branch higher than previous ones used.
154. When committing the modules file, a pre-commit check should be done to
verify the validity of the new modules file before allowing it to be
committed. This could easily be done by adding an option to mkmodules
to perform the verification.
155. The options for "cvs history" are mutually exclusive, even though
useful queries can be done if they are not, as in specifying both a
module and a tag. A workaround is to specify the module, then run the
output through grep to only display lines that begin with T, which are
tag lines.
156. Also, how hard would it be to allow continuation lines in the
{commit,rcs,log}info files? It would probably be useful with all of
the various flags that are now available, or if somebody has a lot of
files to put into a module.
157. The "cvs release" command does not understand about module names with
the same flexibility that the "checkout" and "rdiff" commands do.
It should, though, since it's confusing right now.
158. If I do a recursive commit and find that the same RCS file is checked
out (and modified!) in two different places within my checked-out
files (but within the realm of a single "commit"), CVS will commit the
first change, then overwrite that change with the second change. We
should catch this (typically unusual) case and issue an appropriate
diagnostic and die.
159. On "update", when a merge is done, CVS should remember that your file
was merged into and should keep reminding you of this fact until you
actually look at the file (change its access time). Once you do this,
it should go back to being a normal, unmodified file. This way, after
a big update, you can run update again to see which files just got
merged and may need attention.
160. The checks that the commit command does should be extended to make
sure that the revision that we will lock is not already locked by
someone else. Maybe it should also lock the new revision if the old
revision was already locked by the user as well, thus moving the lock
forward after the commit.
161. The date parser included with CVS (lib/getdate.y) does not support
such RCS-supported dates as "1992/03/07". It probably should.
163. The rtag/tag commands should have an option that removes the specified
tag from any file that is in the attic. This allows one to re-use a
tag (like "Mon", "Tue", ...) all the time and still have it tag the
real main-line code.
164. The *info files should allow multiple ocurrences of $CVSROOT and/or
other cvs variables. They probably should *not* expand environment
variables, as their behavior probably should not depend on who is
running CVS.
165. The "import" command will create RCS files automatically, but will
screw-up when trying to create long file names on short file name
file systems. Perhaps import should be a bit more cautious.
166. There really needs to be a "Getting Started" document which describes
some of the new CVS philosophies. Folks coming straight from SCCS or
RCS might be confused by "cvs import". Also need to explain:
- How one might setup their $CVSROOT
- What all the tags mean in an "import" command
- Tags are important; revision numbers are not
167. "cvs log" doesn't understand about CVS magic branch numbers. As such,
the command:
cvs log -r1.63.2
cvs log -rC2
where "C2" is a magic branch that resolves to 1.63.2 do not print the
same things. Sigh.
169. We are using CVS as the configuration control for a software reuse library.
What we do is do system calls passing the needed arguments. In the next
release, it would be nice to see an option to put cvs .o files into a
archive library with an API. This enhancement would go nicely with the
notion of being able to integrate tools into a large software engineering
environment.
170. Is there an "info" file that can be invoked when a file is checked out, or
updated ? What I want to do is to advise users, particularly novices, of
the state of their working source whenever they check something out, as
a sanity check.
For example, I've written a perl script which tells you what branch you're
on, if any. Hopefully this will help guard against mistaken checkins to
the trunk, or to the wrong branch. I suppose I can do this in
"commitinfo", but it'd be nice to advise people before they edit their
files.
It would also be nice if there was some sort of "verboseness" switch to
the checkout and update commands that could turn this invocation of the
script off, for mature users.
173. We have a tagged branch in CVS. How do we get the version of that branch
(for an entire directory) that corresponds to the files on that branch on a
certain day? I'd like to specify BOTH -r and -D to 'cvs checkout', but I
can't. It looks like I can only specify the date for the main line (as
opposed to any branches). True? Any workarounds to get what I need?
174. I would like to see "cvs release" modified so that it only removes files
which are known to CVS - all the files in the repository, plus those which
are listed in .cvsignore. This way, if you do leave something valuable in
a source tree you can "cvs release -d" the tree and your non-CVS goodies
are still there. If a user is going to leave non-CVS files in their source
trees, they really should have to clean them up by hand.
175. And, in the feature request department, I'd dearly love a command-line
interface to adding a new module to the CVSROOT/modules file.
176. If you use the -i flag in the modules file, you can control access
to source code; this is a Good Thing under certain circumstances. I
just had a nasty thought, and on experiment discovered that the
filter specified by -i is _not_ run before a cvs admin command; as
this allows a user to go behind cvs's back and delete information
(cvs admin -o1.4 file) this seems like a serious problem.
177. We've got some external vendor source that sits under a source code
hierarchy, and when we do a cvs update, it gets wiped out because
its tag is different from the "main" distribution. I've tried to
use "-I" to ignore the directory, as well as .cvsignore, but this
doesn't work.
179. "cvs admin" does not log its actions with loginfo, nor does it check
whether the action is allowed with commitinfo. It should.

View file

@ -1,10 +1,14 @@
# $Id: Makefile,v 1.3 1995/12/11 01:23:42 peter Exp $
# $Id: Makefile,v 1.4 1995/12/11 01:58:47 peter Exp $
SUBDIR= pcl-cvs
.include "${.CURDIR}/../Makefile.inc"
SCRIPTS= ccvs-rsh rcs2log clmerge cln_hist commit_prep cvs_acls cvscheck \
.PATH: ${CVSDIR}/contrib
.PATH: ${CVSDIR}/man
SCRIPTS= rcs2log clmerge cln_hist commit_prep cvs_acls cvscheck \
log log_accum mfpipe rcs-to-cvs rcs2log rcslock sccs2rcs \
easy-import
# easy-import
FILES= README cvscheck.man cvshelp.man descend.man intro.doc
@ -27,11 +31,14 @@ all: ${SCRIPTS}
beforeinstall:
.for file in ${SCRIPTS}
${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
${SCRIPTS} ${DESTDIR}${EXAMPDIR}/contrib
${file} ${DESTDIR}${EXAMPDIR}/contrib
.endfor
.for file in ${FILES}
cd ${.CURDIR} ; \
${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 644 \
${FILES} ${DESTDIR}${EXAMPDIR}/contrib
${CVSDIR}/contrib/${file} ${DESTDIR}${EXAMPDIR}/contrib
.endfor
.include "../../Makefile.inc"
.include <bsd.prog.mk>

View file

@ -1,91 +0,0 @@
$CVSid: @(#)README 1.12 94/09/25 $
This "contrib" directory is a place holder for code/scripts sent to
me by contributors around the world. This README file will be kept
up-to-date from release to release. BUT, I must point out that these
contributions are really, REALLY UNSUPPORTED. In fact, I probably
don't even know what they do. Nor do I guarantee to have tried them,
or ported them to work with this CVS distribution. If you have questions,
you might contact the author, but you should not necessarily expect
a reply. USE AT YOUR OWN RISK -- and all that stuff.
Contents of this directory:
README This file.
log A perl script suitable for including in your
$CVSROOT/CVSROOT/loginfo file for logging commit
changes. Includes the RCS revision of the change
as part of the log.
Contributed by Kevin Samborn <samborn@sunrise.com>.
pcl-cvs A directory that contains GNU Emacs lisp code which
implements a CVS-mode for emacs.
Contributed by Per Cederqvist <ceder@lysator.liu.se>.
commit_prep A perl script, to be combined with log_accum.pl, to
log_accum provide for a way to combine the individual log
messages of a multi-directory "commit" into a
single log message, and mail the result somewhere.
Can also do other checks for $Id and that you are
committing the correct revision of the file.
Read the comments carefully.
Contributed by David Hampton <hampton@cisco.com>.
mfpipe Another perl script for logging. Allows you to
pipe the log message to a file and/or send mail
to some alias.
Contributed by John Clyne <clyne@niwot.scd.ucar.edu>.
rcs-to-cvs Script to import sources that may have been under
RCS control already.
Contributed by Per Cederqvist <ceder@lysator.liu.se>.
cvscheck Identifies files added, changed, or removed in a
cvscheck.man checked out CVS tree; also notices unknown files.
Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
cvshelp.man An introductory manual page written by Lowell Skoog
<fluke!lowell@uunet.uu.net>. It is most likely
out-of-date relative to CVS 1.3, but still may be
useful.
dirfns A shar file which contains some code that might
help your system support opendir/readdir/closedir,
if it does not already.
Copied from the C-News distribution.
rcslock A perl script that can be added to your commitinfo
file that tries to determine if your RCS file is
currently locked by someone else, as might be the
case for a binary file.
Contributed by John Rouillard <rouilj@cs.umb.edu>.
ccvs-rsh A Perl script which allows "rsh pipelines" to
be built in order to use Cyclic CVS from
behind some varieties of firewall.
cvs_acls A perl script that implements Access Control Lists
by using the "commitinfo" hook provided with the
"cvs commit" command.
Contributed by David G. Grubbs <dgg@ksr.com>.
descend A shell script that can be used to recursively
descend.man descend through a directory. In CVS 1.2, this was
very useful, since many of the commands were not
recursive. In CVS 1.3 (and later), however, most of
the commands are recursive. However, this may still
come in handy.
Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
cln_hist A perl script to compress your
$CVSROOT/CVSROOT/history file, as it can grow quite
large after extended use.
Contributed by David G. Grubbs <dgg@ksr.com>
sccs2rcs A C-shell script that can convert (some) SCCS files
into RCS files, retaining the info contained in the
SCCS file (like dates, author, and log message).
Contributed by Ken Cox <kenstir@viewlogic.com>.
intro.doc A user's view of what you need to know to get
started with CVS.
Contributed by <Steven.Pemberton@cwi.nl>.
rcs2sccs A shell script to convert simple RCS files into
SCCS files, originally gleaned off the network
somewhere (originally by "kenc") and modified by
Jerry Jelinek <jerry@rmtc.Central.Sun.COM> and
Brian Berliner <berliner@sun.com> to increase
robustness and add support for one-level of branches.
rcs2log A shell script to create a ChangeLog-format file
given only a set of RCS files.
Contributed by Paul Eggert <eggert@twinsun.com>.
clmerge A perl script to handle merge conflicts in GNU
style ChangeLog files .
Contributed by Tom Tromey <tromey@busco.lanl.gov>.
checklog.pl extract your commits from commitlogs archive

View file

@ -1,97 +0,0 @@
#! xPERL_PATHx
# The version of the remote shell program on some Linuxes, at least,
# misuses GNU getopt in such a way that it plucks arguments to rsh
# that look like command-line switches from anywhere in rsh's
# arguments. This is the Wrong Thing to do, and causes older versions
# of CCVS to break.
# In addition, if we live behind a firewall and have to construct a
# "pipeline" of rshes through different machines in order to get to
# the outside world, each rshd along the way undoes the hard work CCVS
# does to put the command to be executed at the far end into a single
# argument. Sigh.
# This script is a very minimal wrapper to rsh which makes sure that
# the commands to be executed remotely are packed into a single
# argument before we call exec(). It works on the idea of a "proxy
# chain", which is a set of machines you go through to get to the CCVS
# server machine.
# Each host you go through before you reach the CCVS server machine
# should have a copy of this script somewhere (preferably accessible
# directly from your PATH envariable). In addition, each host you go
# through before you reach the firewall should have the CVS_PROXY_HOST
# envariable set to the next machine in the chain, and CVS_PROXY_USER
# set if necessary.
# This really isn't as complex as it sounds. Honest.
# Bryan O'Sullivan <bos@serpentine.com> April 1995
$usage = "usage: ccvs-rsh hostname [-l username] command [...]\n";
if ($#ARGV < 1) {
print STDERR $usage;
exit 1;
}
# Try to pick a sane version of the remote shell command to run. This
# only understands BSD and Linux machines; if your remote shell is
# called "remsh" under some System V (e.g. HP-SUX), you should edit
# the line manually to suit yourself.
$rsh = (-x "/usr/ucb/rsh") ? "/usr/ucb/rsh" : "/usr/bin/rsh";
# If you are not rshing directly to the CCVS server machine, make the
# following variable point at ccvs-rsh on the next machine in the
# proxy chain. If it's accessible through the PATH envariable, you
# can just set this to "ccvs-rsh".
$ccvs_rsh = "ccvs-rsh";
# There shouldn't be any user-serviceable parts beyond this point.
$host = $ARGV[0];
if ($ARGV[1] eq "-l") {
if ($#ARGV < 3) {
print STDERR $usage;
exit 1;
}
$user = $ARGV[2];
$cbase = 3;
} else {
$cbase = 1;
}
# You might think you shoul be able to do something like
# $command = join(' ', $ARGV[$cbase..$#ARGV]);
# to achieve the effect of the following block of code, but it doesn't
# work under Perl 4 on Linux, at least. Sigh.
$command = $ARGV[$cbase];
for ($cbase++; $cbase <= $#ARGV; $cbase++) {
$command .= " " . $ARGV[$cbase];
}
if (defined $ENV{"CVS_PROXY_HOST"}) {
$command = (defined $user)
? "$ccvs_rsh $host -l $user $command"
: "$ccvs_rsh $host $command";
if (defined $ENV{"CVS_PROXY_USER"}) {
exec ($rsh, $ENV{"CVS_PROXY_HOST"}, "-l", $ENV{"CVS_PROXY_USER"},
$command);
} else {
exec ($rsh, $ENV{"CVS_PROXY_HOST"}, $command);
}
} elsif (defined $user) {
exec ($rsh, $host, "-l", $user, $command);
} else {
if (defined $ENV{"CVS_PROXY_USER"}) {
exec ($rsh, $host, "-l", $ENV{"CVS_PROXY_USER"}, $command);
} else {
exec ($rsh, $host, $command);
}
}

View file

@ -1,34 +0,0 @@
#!/usr/bin/perl
# Copyright (c) Wolfram Schneider <wosch@freebsd.org>. June 1996, Berlin.
#
# checklog - extract your commits from commitlogs archive
#
# checklog username /a/cvs/CVSROOT/commitlogs/*[a-y]
# zcat /a/cvs/CVSROOT/commitlogs/*.gz | checklog [username]
#
# $Id: checklog.pl,v 1.2 1996/06/27 12:54:25 wosch Exp $
# your name or first argument
if ($ARGV[0]) {
$name = $ARGV[0]; shift @ARGV;
warn "Is this really a username: `$name' ?\n"
unless $name =~ /^[a-z0-9]+$/;
} else {
$name = `whoami`; chop $name;
}
# date string 96/02/18 10:44:59
$date = '[0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]';
$flag = 0;
while(<>) {
if (/^[a-z]/) { # start of a commit
if (m%^$name\s+$date$%o) { # it's *your* commit
$flag = 1;
} else {
$flag = 0;
}
}
print if $flag;
}

View file

@ -1,152 +0,0 @@
#! xPERL_PATHx
# Merge conflicted ChangeLogs
# tromey Mon Aug 15 1994
# Usage is:
#
# cl-merge [-i] file ...
#
# With -i, it works in place (backups put in a ~ file). Otherwise the
# merged ChangeLog is printed to stdout.
# Please report any bugs to me. I wrote this yesterday, so there are no
# guarantees about its performance. I recommend checking its output
# carefully. If you do send a bug report, please include the failing
# ChangeLog, so I can include it in my test suite.
#
# Tom
# ---
# tromey@busco.lanl.gov Member, League for Programming Freedom
# Sadism and farce are always inexplicably linked.
# -- Alexander Theroux
# Month->number mapping. Used for sorting.
%months = ('Jan', 0,
'Feb', 1,
'Mar', 2,
'Apr', 3,
'May', 4,
'Jun', 5,
'Jul', 6,
'Aug', 7,
'Sep', 8,
'Oct', 9,
'Nov', 10,
'Dec', 11);
# If '-i' is given, do it in-place.
if ($ARGV[0] eq '-i') {
shift (@ARGV);
$^I = '~';
}
$lastkey = '';
$lastval = '';
$conf = 0;
%conflist = ();
$tjd = 0;
# Simple state machine. The states:
#
# 0 Not in conflict. Just copy input to output.
# 1 Beginning an entry. Next non-blank line is key.
# 2 In entry. Entry beginner transitions to state 1.
while (<>) {
if (/^<<<</ || /^====/) {
# Start of a conflict.
# Copy last key into array.
if ($lastkey ne '') {
$conflist{$lastkey} = $lastval;
$lastkey = '';
$lastval = '';
}
$conf = 1;
} elsif (/^>>>>/) {
# End of conflict. Output.
# Copy last key into array.
if ($lastkey ne '') {
$conflist{$lastkey} = $lastval;
$lastkey = '';
$lastval = '';
}
foreach (reverse sort clcmp keys %conflist) {
print STDERR "doing $_" if $tjd;
print $_;
print $conflist{$_};
}
$lastkey = '';
$lastval = '';
$conf = 0;
%conflist = ();
} elsif ($conf == 1) {
# Beginning an entry. Skip empty lines. Error if not a real
# beginner.
if (/^$/) {
# Empty line; just skip at this point.
} elsif (/^[MTWFS]/) {
# Looks like the name of a day; assume opener and move to
# "in entry" state.
$lastkey = $_;
$conf = 2;
print STDERR "found $_" if $tjd;
} else {
die ("conflict crosses entry boundaries: $_");
}
} elsif ($conf == 2) {
# In entry. Copy into variable until we see beginner line.
if (/^[MTWFS]/) {
# Entry beginner line.
# Copy last key into array.
if ($lastkey ne '') {
$conflist{$lastkey} = $lastval;
$lastkey = '';
$lastval = '';
}
$lastkey = $_;
print STDERR "found $_" if $tjd;
$lastval = '';
} else {
$lastval .= $_;
}
} else {
# Just copy.
print;
}
}
# Compare ChangeLog time strings like <=>.
#
# 0 1 2 3
# Thu Aug 11 13:22:42 1994 Tom Tromey (tromey@creche.colorado.edu)
# 0123456789012345678901234567890
#
sub clcmp {
# First check year.
$r = substr ($a, 20, 4) <=> substr ($b, 20, 4);
# Now check month.
$r = $months{substr ($a, 4, 3)} <=> $months{substr ($b, 4, 3)} if !$r;
# Now check day.
$r = substr ($a, 8, 2) <=> substr ($b, 8, 2) if !$r;
# Now check time (3 parts).
$r = substr ($a, 11, 2) <=> substr ($b, 11, 2) if !$r;
$r = substr ($a, 14, 2) <=> substr ($b, 14, 2) if !$r;
$r = substr ($a, 17, 2) <=> substr ($b, 17, 2) if !$r;
$r;
}

View file

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

View file

@ -1,216 +0,0 @@
#! xPERL_PATHx
# -*-Perl-*-
#
#ident "@(#)cvs/contrib:$Name: $:$Id: commit_prep.pl,v 1.2 1995/07/10 02:01:29 kfogel Exp $"
#
# Perl filter to handle pre-commit checking of files. This program
# records the last directory where commits will be taking place for
# use by the log_accum.pl script. For new files, it forces the
# existence of a RCS "Id" keyword in the first ten lines of the file.
# For existing files, it checks version number in the "Id" line to
# prevent losing changes because an old version of a file was copied
# into the direcory.
#
# Possible future enhancements:
#
# Check for cruft left by unresolved conflicts. Search for
# "^<<<<<<<$", "^-------$", and "^>>>>>>>$".
#
# Look for a copyright and automagically update it to the
# current year. [[ bad idea! -- woods ]]
#
#
# Contributed by David Hampton <hampton@cisco.com>
#
# Hacked on lots by Greg A. Woods <woods@web.net>
#
# Configurable options
#
# Constants (remember to protect strings from RCS keyword substitution)
#
$LAST_FILE = "/tmp/#cvs.lastdir"; # must match name in log_accum.pl
$ENTRIES = "CVS/Entries";
# Patterns to find $Log keywords in files
#
$LogString1 = "\\\$\\Log: .* \\\$";
$LogString2 = "\\\$\\Log\\\$";
$NoLog = "%s - contains an RCS \$Log keyword. It must not!\n";
# pattern to match an RCS Id keyword line with an existing ID
#
$IDstring = "\"@\\(#\\)[^:]*:.*\\\$\Id: .*\\\$\"";
$NoId = "
%s - Does not contain a properly formatted line with the keyword \"Id:\".
I.e. no lines match \"" . $IDstring . "\".
Please see the template files for an example.\n";
# pattern to match an RCS Id keyword line for a new file (i.e. un-expanded)
#
$NewId = "\"@(#)[^:]*:.*\\$\Id\\$\"";
$NoName = "
%s - The ID line should contain only \"@(#)module/path:\$Name\$:\$\Id\$\"
for a newly created file.\n";
$BadName = "
%s - The file name '%s' in the ID line does not match
the actual filename.\n";
$BadVersion = "
%s - How dare you!!! You replaced your copy of the file '%s',
which was based upon version %s, with an %s version based
upon %s. Please move your '%s' out of the way, perform an
update to get the current version, and them merge your changes
into that file, then try the commit again.\n";
#
# Subroutines
#
sub write_line {
local($filename, $line) = @_;
open(FILE, ">$filename") || die("Cannot open $filename, stopped");
print(FILE $line, "\n");
close(FILE);
}
sub check_version {
local($i, $id, $rname, $version);
local($filename, $cvsversion) = @_;
open(FILE, "<$filename") || return(0);
@all_lines = ();
$idpos = -1;
$newidpos = -1;
for ($i = 0; <FILE>; $i++) {
chop;
push(@all_lines, $_);
if ($_ =~ /$IDstring/) {
$idpos = $i;
}
if ($_ =~ /$NewId/) {
$newidpos = $i;
}
}
if (grep(/$LogString1/, @all_lines) || grep(/$LogString2/, @all_lines)) {
print STDERR sprintf($NoLog, $filename);
return(1);
}
if ($debug != 0) {
print STDERR sprintf("file = %s, version = %d.\n", $filename, $cvsversion{$filename});
}
if ($cvsversion{$filename} == 0) {
if ($newidpos != -1 && $all_lines[$newidpos] !~ /$NewId/) {
print STDERR sprintf($NoName, $filename);
return(1);
}
return(0);
}
if ($idpos == -1) {
print STDERR sprintf($NoId, $filename);
return(1);
}
$line = $all_lines[$idpos];
$pos = index($line, "Id: ");
if ($debug != 0) {
print STDERR sprintf("%d in '%s'.\n", $pos, $line);
}
($id, $rname, $version) = split(' ', substr($line, $pos));
if ($rname ne "$filename,v") {
print STDERR sprintf($BadName, $filename, substr($rname, 0, length($rname)-2));
return(1);
}
if ($cvsversion{$filename} < $version) {
print STDERR sprintf($BadVersion, $filename, $filename, $cvsversion{$filename},
"newer", $version, $filename);
return(1);
}
if ($cvsversion{$filename} > $version) {
print STDERR sprintf($BadVersion, $filename, $filename, $cvsversion{$filename},
"older", $version, $filename);
return(1);
}
return(0);
}
#
# Main Body
#
$id = getpgrp(); # You *must* use a shell that does setpgrp()!
# Check each file (except dot files) for an RCS "Id" keyword.
#
$check_id = 0;
# Record the directory for later use by the log_accumulate stript.
#
$record_directory = 0;
# parse command line arguments
#
while (@ARGV) {
$arg = shift @ARGV;
if ($arg eq '-d') {
$debug = 1;
print STDERR "Debug turned on...\n";
} elsif ($arg eq '-c') {
$check_id = 1;
} elsif ($arg eq '-r') {
$record_directory = 1;
} else {
push(@files, $arg);
}
}
$directory = shift @files;
if ($debug != 0) {
print STDERR "dir - ", $directory, "\n";
print STDERR "files - ", join(":", @files), "\n";
print STDERR "id - ", $id, "\n";
}
# Suck in the CVS/Entries file
#
open(ENTRIES, $ENTRIES) || die("Cannot open $ENTRIES.\n");
while (<ENTRIES>) {
local($filename, $version) = split('/', substr($_, 1));
$cvsversion{$filename} = $version;
}
# Now check each file name passed in, except for dot files. Dot files
# are considered to be administrative files by this script.
#
if ($check_id != 0) {
$failed = 0;
foreach $arg (@files) {
if (index($arg, ".") == 0) {
next;
}
$failed += &check_version($arg);
}
if ($failed) {
print STDERR "\n";
exit(1);
}
}
# Record this directory as the last one checked. This will be used
# by the log_accumulate script to determine when it is processing
# the final directory of a multi-directory commit.
#
if ($record_directory != 0) {
&write_line("$LAST_FILE.$id", $directory);
}
exit(0);

View file

@ -1,81 +0,0 @@
;; -*- lisp-interaction -*-
;; -*- emacs-lisp -*-
;;
;;
;; originally from...
;; Rich's personal .emacs file. feel free to copy.
;;
;; Last Mod Wed Feb 5 16:11:47 PST 1992, by rich@cygnus.com
;;
;;
;;
;; This section sets constants used by c-mode for formating
;;
;;
;; If `c-auto-newline' is non-`nil', newlines are inserted both
;;before and after braces that you insert, and after colons and semicolons.
;;Correct C indentation is done on all the lines that are made this way.
(setq c-auto-newline nil)
;;*Non-nil means TAB in C mode should always reindent the current line,
;;regardless of where in the line point is when the TAB command is used.
;;It might be desirable to set this to nil for CVS, since unlike GNU
;; CVS often uses comments over to the right separated by TABs.
;; Depends some on whether you're in the habit of using TAB to
;; reindent.
;(setq c-tab-always-indent nil)
;;; It seems to me that
;;; `M-x set-c-style BSD RET'
;;; or
;;; (set-c-style "BSD")
;;; takes care of the indentation parameters correctly.
;; C does not have anything analogous to particular function names for which
;;special forms of indentation are desirable. However, it has a different
;;need for customization facilities: many different styles of C indentation
;;are in common use.
;;
;; There are six variables you can set to control the style that Emacs C
;;mode will use.
;;
;;`c-indent-level'
;; Indentation of C statements within surrounding block. The surrounding
;; block's indentation is the indentation of the line on which the
;; open-brace appears.
(setq c-indent-level 4)
;;`c-continued-statement-offset'
;; Extra indentation given to a substatement, such as the then-clause of
;; an if or body of a while.
(setq c-continued-statement-offset 4)
;;`c-brace-offset'
;; Extra indentation for line if it starts with an open brace.
(setq c-brace-offset -4)
;;`c-brace-imaginary-offset'
;; An open brace following other text is treated as if it were this far
;; to the right of the start of its line.
(setq c-brace-imaginary-offset 0)
;;`c-argdecl-indent'
;; Indentation level of declarations of C function arguments.
(setq c-argdecl-indent 4)
;;`c-label-offset'
;; Extra indentation for line that is a label, or case or default.
(setq c-label-offset -4)
;;;; eof

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,481 +0,0 @@
echo 'directory.3':
sed 's/^X//' >'directory.3' <<'!'
X.TH DIRECTORY 3 imported
X.DA 9 Oct 1985
X.SH NAME
Xopendir, readdir, telldir, seekdir, rewinddir, closedir \- high-level directory operations
X.SH SYNOPSIS
X.B #include <sys/types.h>
X.br
X.B #include <ndir.h>
X.PP
X.SM
X.B DIR
X.B *opendir(filename)
X.br
X.B char *filename;
X.PP
X.SM
X.B struct direct
X.B *readdir(dirp)
X.br
X.B DIR *dirp;
X.PP
X.SM
X.B long
X.B telldir(dirp)
X.br
X.B DIR *dirp;
X.PP
X.SM
X.B seekdir(dirp, loc)
X.br
X.B DIR *dirp;
X.br
X.B long loc;
X.PP
X.SM
X.B rewinddir(dirp)
X.br
X.B DIR *dirp;
X.PP
X.SM
X.B closedir(dirp)
X.br
X.B DIR *dirp;
X.SH DESCRIPTION
XThis library provides high-level primitives for directory scanning,
Xsimilar to those available for 4.2BSD's (very different) directory system.
X.\"The purpose of this library is to simulate
X.\"the new flexible length directory names of 4.2bsd UNIX
X.\"on top of the old directory structure of v7.
XIt incidentally provides easy portability to and from 4.2BSD (insofar
Xas such portability is not compromised by other 4.2/VAX dependencies).
X.\"It allows programs to be converted immediately
X.\"to the new directory access interface,
X.\"so that they need only be relinked
X.\"when moved to 4.2bsd.
X.\"It is obtained with the loader option
X.\".BR \-lndir .
X.PP
X.I Opendir
Xopens the directory named by
X.I filename
Xand associates a
X.I directory stream
Xwith it.
X.I Opendir
Xreturns a pointer to be used to identify the
X.I directory stream
Xin subsequent operations.
XThe pointer
X.SM
X.B NULL
Xis returned if
X.I filename
Xcannot be accessed or is not a directory.
X.PP
X.I Readdir
Xreturns a pointer to the next directory entry.
XIt returns
X.B NULL
Xupon reaching the end of the directory or detecting
Xan invalid
X.I seekdir
Xoperation.
X.PP
X.I Telldir
Xreturns the current location associated with the named
X.I directory stream.
X.PP
X.I Seekdir
Xsets the position of the next
X.I readdir
Xoperation on the
X.I directory stream.
XThe new position reverts to the one associated with the
X.I directory stream
Xwhen the
X.I telldir
Xoperation was performed.
XValues returned by
X.I telldir
Xare good only for the lifetime of the DIR pointer from
Xwhich they are derived.
XIf the directory is closed and then reopened,
Xthe
X.I telldir
Xvalue may be invalidated
Xdue to undetected directory compaction in 4.2BSD.
XIt is safe to use a previous
X.I telldir
Xvalue immediately after a call to
X.I opendir
Xand before any calls to
X.I readdir.
X.PP
X.I Rewinddir
Xresets the position of the named
X.I directory stream
Xto the beginning of the directory.
X.PP
X.I Closedir
Xcauses the named
X.I directory stream
Xto be closed,
Xand the structure associated with the DIR pointer to be freed.
X.PP
XA
X.I direct
Xstructure is as follows:
X.PP
X.RS
X.nf
Xstruct direct {
X /* unsigned */ long d_ino; /* inode number of entry */
X unsigned short d_reclen; /* length of this record */
X unsigned short d_namlen; /* length of string in d_name */
X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
X};
X.fi
X.RE
X.PP
XThe
X.I d_reclen
Xfield is meaningless in non-4.2BSD systems and should be ignored.
XThe use of a
X.I long
Xfor
X.I d_ino
Xis also a 4.2BSDism;
X.I ino_t
X(see
X.IR types (5))
Xshould be used elsewhere.
XThe macro
X.I DIRSIZ(dp)
Xgives the minimum memory size needed to hold the
X.I direct
Xvalue pointed to by
X.IR dp ,
Xwith the minimum necessary allocation for
X.IR d_name .
X.PP
XThe preferred way to search the current directory for entry ``name'' is:
X.PP
X.RS
X.nf
X len = strlen(name);
X dirp = opendir(".");
X if (dirp == NULL) {
X fprintf(stderr, "%s: can't read directory .\\n", argv[0]);
X return NOT_FOUND;
X }
X while ((dp = readdir(dirp)) != NULL)
X if (dp->d_namlen == len && strcmp(dp->d_name, name) == 0) {
X closedir(dirp);
X return FOUND;
X }
X closedir(dirp);
X return NOT_FOUND;
X.RE
X.\".SH LINKING
X.\"This library is accessed by specifying ``-lndir'' as the
X.\"last argument to the compile line, e.g.:
X.\".PP
X.\" cc -I/usr/include/ndir -o prog prog.c -lndir
X.SH "SEE ALSO"
Xopen(2),
Xclose(2),
Xread(2),
Xlseek(2)
X.SH HISTORY
XWritten by
XKirk McKusick at Berkeley (ucbvax!mckusick).
XMiscellaneous bug fixes from elsewhere.
XThe size of the data structure has been decreased to avoid excessive
Xspace waste under V7 (where filenames are 14 characters at most).
XFor obscure historical reasons, the include file is also available
Xas
X.IR <ndir/sys/dir.h> .
XThe Berkeley version lived in a separate library (\fI\-lndir\fR),
Xwhereas ours is
Xpart of the C library, although the separate library is retained to
Xmaximize compatibility.
X.PP
XThis manual page has been substantially rewritten to be informative in
Xthe absence of a 4.2BSD manual.
X.SH BUGS
XThe
X.I DIRSIZ
Xmacro actually wastes a bit of space due to some padding requirements
Xthat are an artifact of 4.2BSD.
X.PP
XThe returned value of
X.I readdir
Xpoints to a static area that will be overwritten by subsequent calls.
X.PP
XThere are some unfortunate name conflicts with the \fIreal\fR V7
Xdirectory structure definitions.
!
echo 'dir.h':
sed 's/^X//' >'dir.h' <<'!'
X/* dir.h 4.4 82/07/25 */
X
X/*
X * A directory consists of some number of blocks of DIRBLKSIZ
X * bytes, where DIRBLKSIZ is chosen such that it can be transferred
X * to disk in a single atomic operation (e.g. 512 bytes on most machines).
X *
X * Each DIRBLKSIZ byte block contains some number of directory entry
X * structures, which are of variable length. Each directory entry has
X * a struct direct at the front of it, containing its inode number,
X * the length of the entry, and the length of the name contained in
X * the entry. These are followed by the name padded to a 4 byte boundary
X * with null bytes. All names are guaranteed null terminated.
X * The maximum length of a name in a directory is MAXNAMLEN.
X *
X * The macro DIRSIZ(dp) gives the amount of space required to represent
X * a directory entry. Free space in a directory is represented by
X * entries which have dp->d_reclen >= DIRSIZ(dp). All DIRBLKSIZ bytes
X * in a directory block are claimed by the directory entries. This
X * usually results in the last entry in a directory having a large
X * dp->d_reclen. When entries are deleted from a directory, the
X * space is returned to the previous entry in the same directory
X * block by increasing its dp->d_reclen. If the first entry of
X * a directory block is free, then its dp->d_ino is set to 0.
X * Entries other than the first in a directory do not normally have
X * dp->d_ino set to 0.
X */
X#define DIRBLKSIZ 512
X#ifdef VMUNIX
X#define MAXNAMLEN 255
X#else
X#define MAXNAMLEN 14
X#endif
X
Xstruct direct {
X /* unsigned */ long d_ino; /* inode number of entry */
X unsigned short d_reclen; /* length of this record */
X unsigned short d_namlen; /* length of string in d_name */
X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
X};
X
X/*
X * The DIRSIZ macro gives the minimum record length which will hold
X * the directory entry. This requires the amount of space in struct direct
X * without the d_name field, plus enough space for the name with a terminating
X * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
X */
X#undef DIRSIZ
X#define DIRSIZ(dp) \
X ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
X
X#ifndef KERNEL
X/*
X * Definitions for library routines operating on directories.
X */
Xtypedef struct _dirdesc {
X int dd_fd;
X long dd_loc;
X long dd_size;
X char dd_buf[DIRBLKSIZ];
X} DIR;
X#ifndef NULL
X#define NULL 0
X#endif
Xextern DIR *opendir();
Xextern struct direct *readdir();
Xextern long telldir();
X#ifdef void
Xextern void seekdir();
Xextern void closedir();
X#endif
X#define rewinddir(dirp) seekdir((dirp), (long)0)
X#endif KERNEL
!
echo 'makefile':
sed 's/^X//' >'makefile' <<'!'
XDIR = closedir.o opendir.o readdir.o seekdir.o telldir.o
XCFLAGS=-O -I. -Dvoid=int
XDEST=..
X
Xall: $(DIR)
X
Xmv: $(DIR)
X mv $(DIR) $(DEST)
X
Xcpif: dir.h
X cp dir.h /usr/include/ndir.h
X
Xclean:
X rm -f *.o
!
echo 'closedir.c':
sed 's/^X//' >'closedir.c' <<'!'
Xstatic char sccsid[] = "@(#)closedir.c 4.2 3/10/82";
X
X#include <sys/types.h>
X#include <dir.h>
X
X/*
X * close a directory.
X */
Xvoid
Xclosedir(dirp)
X register DIR *dirp;
X{
X close(dirp->dd_fd);
X dirp->dd_fd = -1;
X dirp->dd_loc = 0;
X free((char *)dirp);
X}
!
echo 'opendir.c':
sed 's/^X//' >'opendir.c' <<'!'
X/* Copyright (c) 1982 Regents of the University of California */
X
Xstatic char sccsid[] = "@(#)opendir.c 4.4 11/12/82";
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <dir.h>
X
X/*
X * open a directory.
X */
XDIR *
Xopendir(name)
X char *name;
X{
X register DIR *dirp;
X register int fd;
X struct stat statbuf;
X char *malloc();
X
X if ((fd = open(name, 0)) == -1)
X return NULL;
X if (fstat(fd, &statbuf) == -1 || !(statbuf.st_mode & S_IFDIR)) {
X close(fd);
X return NULL;
X }
X if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
X close (fd);
X return NULL;
X }
X dirp->dd_fd = fd;
X dirp->dd_loc = 0;
X dirp->dd_size = 0; /* so that telldir will work before readdir */
X return dirp;
X}
!
echo 'readdir.c':
sed 's/^X//' >'readdir.c' <<'!'
X/* Copyright (c) 1982 Regents of the University of California */
X
Xstatic char sccsid[] = "@(#)readdir.c 4.3 8/8/82";
X
X#include <sys/types.h>
X#include <dir.h>
X
X/*
X * read an old stlye directory entry and present it as a new one
X */
X#define ODIRSIZ 14
X
Xstruct olddirect {
X ino_t od_ino;
X char od_name[ODIRSIZ];
X};
X
X/*
X * get next entry in a directory.
X */
Xstruct direct *
Xreaddir(dirp)
X register DIR *dirp;
X{
X register struct olddirect *dp;
X static struct direct dir;
X
X for (;;) {
X if (dirp->dd_loc == 0) {
X dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
X DIRBLKSIZ);
X if (dirp->dd_size <= 0) {
X dirp->dd_size = 0;
X return NULL;
X }
X }
X if (dirp->dd_loc >= dirp->dd_size) {
X dirp->dd_loc = 0;
X continue;
X }
X dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc);
X dirp->dd_loc += sizeof(struct olddirect);
X if (dp->od_ino == 0)
X continue;
X dir.d_ino = dp->od_ino;
X strncpy(dir.d_name, dp->od_name, ODIRSIZ);
X dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */
X dir.d_namlen = strlen(dir.d_name);
X dir.d_reclen = DIRBLKSIZ;
X return (&dir);
X }
X}
!
echo 'seekdir.c':
sed 's/^X//' >'seekdir.c' <<'!'
Xstatic char sccsid[] = "@(#)seekdir.c 4.9 3/25/83";
X
X#include <sys/param.h>
X#include <dir.h>
X
X/*
X * seek to an entry in a directory.
X * Only values returned by "telldir" should be passed to seekdir.
X */
Xvoid
Xseekdir(dirp, loc)
X register DIR *dirp;
X long loc;
X{
X long curloc, base, offset;
X struct direct *dp;
X extern long lseek();
X
X curloc = telldir(dirp);
X if (loc == curloc)
X return;
X base = loc & ~(DIRBLKSIZ - 1);
X offset = loc & (DIRBLKSIZ - 1);
X (void) lseek(dirp->dd_fd, base, 0);
X dirp->dd_size = 0;
X dirp->dd_loc = 0;
X while (dirp->dd_loc < offset) {
X dp = readdir(dirp);
X if (dp == NULL)
X return;
X }
X}
!
echo 'telldir.c':
sed 's/^X//' >'telldir.c' <<'!'
Xstatic char sccsid[] = "@(#)telldir.c 4.1 2/21/82";
X
X#include <sys/types.h>
X#include <dir.h>
X
X/*
X * return a pointer into a directory
X */
Xlong
Xtelldir(dirp)
X DIR *dirp;
X{
X long lseek();
X
X return (lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc);
X}
!
echo done

View file

@ -1,112 +0,0 @@
Date: Tue, 16 Jun 1992 17:05:23 +0200
From: Steven.Pemberton@cwi.nl
Message-Id: <9206161505.AA06927.steven@sijs.cwi.nl>
To: berliner@Sun.COM
Subject: cvs
INTRODUCTION TO USING CVS
CVS is a system that lets groups of people work simultaneously on
groups of files (for instance program sources).
It works by holding a central 'repository' of the most recent version
of the files. You may at any time create a personal copy of these
files; if at a later date newer versions of the files are put in the
repository, you can 'update' your copy.
You may edit your copy of the files freely. If new versions of the
files have been put in the repository in the meantime, doing an update
merges the changes in the central copy into your copy.
(It can be that when you do an update, the changes in the
central copy clash with changes you have made in your own
copy. In this case cvs warns you, and you have to resolve the
clash in your copy.)
When you are satisfied with the changes you have made in your copy of
the files, you can 'commit' them into the central repository.
(When you do a commit, if you haven't updated to the most
recent version of the files, cvs tells you this; then you have
to first update, resolve any possible clashes, and then redo
the commit.)
USING CVS
Suppose that a number of repositories have been stored in
/usr/src/cvs. Whenever you use cvs, the environment variable
CVSROOT must be set to this (for some reason):
CVSROOT=/usr/src/cvs
export CVSROOT
TO CREATE A PERSONAL COPY OF A REPOSITORY
Suppose you want a copy of the files in repository 'views' to be
created in your directory src. Go to the place where you want your
copy of the directory, and do a 'checkout' of the directory you
want:
cd $HOME/src
cvs checkout views
This creates a directory called (in this case) 'views' in the src
directory, containing a copy of the files, which you may now work
on to your heart's content.
TO UPDATE YOUR COPY
Use the command 'cvs update'.
This will update your copy with any changes from the central
repository, telling you which files have been updated (their names
are displayed with a U before them), and which have been modified
by you and not yet committed (preceded by an M). You will be
warned of any files that contain clashes, the clashes will be
marked in the file surrounded by lines of the form <<<< and >>>>.
TO COMMIT YOUR CHANGES
Use the command 'cvs commit'.
You will be put in an editor to make a message that describes the
changes that you have made (for future reference). Your changes
will then be added to the central copy.
ADDING AND REMOVING FILES
It can be that the changes you want to make involve a completely
new file, or removing an existing one. The commands to use here
are:
cvs add <filename>
cvs remove <filename>
You still have to do a commit after these commands. You may make
any number of new files in your copy of the repository, but they
will not be committed to the central copy unless you do a 'cvs add'.
OTHER USEFUL COMMANDS AND HINTS
To see the commit messages for files, and who made them, use:
cvs log [filenames]
To see the differences between your version and the central version:
cvs diff [filenames]
To give a file a new name, rename it and do an add and a remove.
To lose your changes and go back to the version from the
repository, delete the file and do an update.
After an update where there have been clashes, your original
version of the file is saved as .#file.version.
All the cvs commands mentioned accept a flag '-n', that doesn't do
the action, but lets you see what would happen. For instance, you
can use 'cvs -n update' to see which files would be updated.
MORE INFORMATION
This is necessarily a very brief introduction. See the manual page
(man cvs) for full details.

View file

@ -1,169 +0,0 @@
#! xPERL_PATHx
# -*-Perl-*-
#
#ident "$CVSid$"
#
# XXX: FIXME: handle multiple '-f logfile' arguments
#
# XXX -- I HATE Perl! This *will* be re-written in shell/awk/sed soon!
#
# Usage: log.pl [[-m user] ...] [-s] -f logfile 'dirname file ...'
#
# -m user - for each user to receive cvs log reports
# (multiple -m's permitted)
# -s - to prevent "cvs status -v" messages
# -f logfile - for the logfile to append to (mandatory,
# but only one logfile can be specified).
# here is what the output looks like:
#
# From: woods@kuma.domain.top
# Subject: CVS update: testmodule
#
# Date: Wednesday November 23, 1994 @ 14:15
# Author: woods
#
# Update of /local/src-CVS/testmodule
# In directory kuma:/home/kuma/woods/work.d/testmodule
#
# Modified Files:
# test3
# Added Files:
# test6
# Removed Files:
# test4
# Log Message:
# - wow, what a test
#
# (and for each file the "cvs status -v" output is appended unless -s is used)
#
# ==================================================================
# File: test3 Status: Up-to-date
#
# Working revision: 1.41 Wed Nov 23 14:15:59 1994
# Repository revision: 1.41 /local/src-CVS/cvs/testmodule/test3,v
# Sticky Options: -ko
#
# Existing Tags:
# local-v2 (revision: 1.7)
# local-v1 (revision: 1.1.1.2)
# CVS-1_4A2 (revision: 1.1.1.2)
# local-v0 (revision: 1.2)
# CVS-1_4A1 (revision: 1.1.1.1)
# CVS (branch: 1.1.1)
$cvsroot = $ENV{'CVSROOT'};
# turn off setgid
#
$) = $(;
$dostatus = 1;
# parse command line arguments
#
while (@ARGV) {
$arg = shift @ARGV;
if ($arg eq '-m') {
$users = "$users " . shift @ARGV;
} elsif ($arg eq '-f') {
($logfile) && die "Too many '-f' args";
$logfile = shift @ARGV;
} elsif ($arg eq '-s') {
$dostatus = 0;
} else {
($donefiles) && die "Too many arguments!\n";
$donefiles = 1;
@files = split(/ /, $arg);
}
}
# the first argument is the module location relative to $CVSROOT
#
$modulepath = shift @files;
$mailcmd = "| Mail -s 'CVS update: $modulepath'";
# Initialise some date and time arrays
#
@mos = (January,February,March,April,May,June,July,August,September,
October,November,December);
@days = (Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday);
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime;
# get a login name for the guy doing the commit....
#
$login = getlogin || (getpwuid($<))[0] || "nobody";
# open log file for appending
#
open(OUT, ">>" . $logfile) || die "Could not open(" . $logfile . "): $!\n";
# send mail, if there's anyone to send to!
#
if ($users) {
$mailcmd = "$mailcmd $users";
open(MAIL, $mailcmd) || die "Could not Exec($mailcmd): $!\n";
}
# print out the log Header
#
print OUT "\n";
print OUT "****************************************\n";
print OUT "Date:\t$days[$wday] $mos[$mon] $mday, 19$year @ $hour:" . sprintf("%02d", $min) . "\n";
print OUT "Author:\t$login\n\n";
if (MAIL) {
print MAIL "\n";
print MAIL "Date:\t$days[$wday] $mos[$mon] $mday, 19$year @ $hour:" . sprintf("%02d", $min) . "\n";
print MAIL "Author:\t$login\n\n";
}
# print the stuff from logmsg that comes in on stdin to the logfile
#
open(IN, "-");
while (<IN>) {
print OUT $_;
if (MAIL) {
print MAIL $_;
}
}
close(IN);
print OUT "\n";
# after log information, do an 'cvs -Qq status -v' on each file in the arguments.
#
if ($dostatus != 0) {
while (@files) {
$file = shift @files;
if ($file eq "-") {
print OUT "[input file was '-']\n";
if (MAIL) {
print MAIL "[input file was '-']\n";
}
last;
}
open(RCS, "-|") || exec 'cvs', '-nQq', 'status', '-v', $file;
while (<RCS>) {
print OUT;
if (MAIL) {
print MAIL;
}
}
close(RCS);
}
}
close(OUT);
die "Write to $logfile failed" if $?;
close(MAIL);
die "Pipe to $mailcmd failed" if $?;
## must exit cleanly
##
exit 0;

View file

@ -1,496 +0,0 @@
#! xPERL_PATHx
# -*-Perl-*-
#
# Perl filter to handle the log messages from the checkin of files in
# a directory. This script will group the lists of files by log
# message, and mail a single consolidated log message at the end of
# the commit.
#
# This file assumes a pre-commit checking program that leaves the
# names of the first and last commit directories in a temporary file.
#
# Contributed by David Hampton <hampton@cisco.com>
#
# hacked greatly by Greg A. Woods <woods@planix.com>
# Usage: log_accum.pl [-d] [-s] [-M module] [[-m mailto] ...] [-f logfile]
# -d - turn on debugging
# -m mailto - send mail to "mailto" (multiple)
# -M modulename - set module name to "modulename"
# -f logfile - write commit messages to logfile too
# -s - *don't* run "cvs status -v" for each file
#
# Configurable options
#
$MAILER = "Mail"; # set this to something that takes "-s"
#
# End user configurable options.
#
# Constants (don't change these!)
#
$STATE_NONE = 0;
$STATE_CHANGED = 1;
$STATE_ADDED = 2;
$STATE_REMOVED = 3;
$STATE_LOG = 4;
$LAST_FILE = "/tmp/#cvs.lastdir";
$CHANGED_FILE = "/tmp/#cvs.files.changed";
$ADDED_FILE = "/tmp/#cvs.files.added";
$REMOVED_FILE = "/tmp/#cvs.files.removed";
$LOG_FILE = "/tmp/#cvs.files.log";
$FILE_PREFIX = "#cvs.files";
#
# Subroutines
#
sub cleanup_tmpfiles {
local($wd, @files);
$wd = `pwd`;
chdir("/tmp") || die("Can't chdir('/tmp')\n");
opendir(DIR, ".");
push(@files, grep(/^$FILE_PREFIX\..*\.$id$/, readdir(DIR)));
closedir(DIR);
foreach (@files) {
unlink $_;
}
unlink $LAST_FILE . "." . $id;
chdir($wd);
}
sub write_logfile {
local($filename, @lines) = @_;
open(FILE, ">$filename") || die("Cannot open log file $filename.\n");
print FILE join("\n", @lines), "\n";
close(FILE);
}
sub append_to_logfile {
local($filename, @lines) = @_;
open(FILE, ">$filename") || die("Cannot open log file $filename.\n");
print FILE join("\n", @lines), "\n";
close(FILE);
}
sub format_names {
local($dir, @files) = @_;
local(@lines);
$format = "\t%-" . sprintf("%d", length($dir)) . "s%s ";
$lines[0] = sprintf($format, $dir, ":");
if ($debug) {
print STDERR "format_names(): dir = ", $dir, "; files = ", join(":", @files), ".\n";
}
foreach $file (@files) {
if (length($lines[$#lines]) + length($file) > 65) {
$lines[++$#lines] = sprintf($format, " ", " ");
}
$lines[$#lines] .= $file . " ";
}
@lines;
}
sub format_lists {
local(@lines) = @_;
local(@text, @files, $lastdir);
if ($debug) {
print STDERR "format_lists(): ", join(":", @lines), "\n";
}
@text = ();
@files = ();
$lastdir = shift @lines; # first thing is always a directory
if ($lastdir !~ /.*\/$/) {
die("Damn, $lastdir doesn't look like a directory!\n");
}
foreach $line (@lines) {
if ($line =~ /.*\/$/) {
push(@text, &format_names($lastdir, @files));
$lastdir = $line;
@files = ();
} else {
push(@files, $line);
}
}
push(@text, &format_names($lastdir, @files));
@text;
}
sub append_names_to_file {
local($filename, $dir, @files) = @_;
if (@files) {
open(FILE, ">>$filename") || die("Cannot open file $filename.\n");
print FILE $dir, "\n";
print FILE join("\n", @files), "\n";
close(FILE);
}
}
sub read_line {
local($line);
local($filename) = @_;
open(FILE, "<$filename") || die("Cannot open file $filename.\n");
$line = <FILE>;
close(FILE);
chop($line);
$line;
}
sub read_logfile {
local(@text);
local($filename, $leader) = @_;
open(FILE, "<$filename");
while (<FILE>) {
chop;
push(@text, $leader.$_);
}
close(FILE);
@text;
}
sub build_header {
local($header);
local($sec,$min,$hour,$mday,$mon,$year) = localtime(time);
$header = sprintf("CVSROOT:\t%s\nModule name:\t%s\nChanges by:\t%s@%s\t%02d/%02d/%02d %02d:%02d:%02d",
$cvsroot,
$modulename,
$login, $hostdomain,
$year%100, $mon+1, $mday,
$hour, $min, $sec);
}
sub mail_notification {
local($name, @text) = @_;
open(MAIL, "| $MAILER -s \"CVS Update: " . $modulename . "\" " . $name);
print MAIL join("\n", @text), "\n";
close(MAIL);
}
sub write_commitlog {
local($logfile, @text) = @_;
open(FILE, ">>$logfile");
print FILE join("\n", @text), "\n";
close(FILE);
}
#
# Main Body
#
# Initialize basic variables
#
$debug = 0;
$id = getpgrp(); # note, you *must* use a shell which does setpgrp()
$state = $STATE_NONE;
$login = getlogin || (getpwuid($<))[0] || "nobody";
chop($hostname = `hostname`);
chop($domainname = `domainname`);
$hostdomain = $hostname . $domainname;
$cvsroot = $ENV{'CVSROOT'};
$do_status = 1;
$modulename = "";
# parse command line arguments (file list is seen as one arg)
#
while (@ARGV) {
$arg = shift @ARGV;
if ($arg eq '-d') {
$debug = 1;
print STDERR "Debug turned on...\n";
} elsif ($arg eq '-m') {
$mailto = "$mailto " . shift @ARGV;
} elsif ($arg eq '-M') {
$modulename = shift @ARGV;
} elsif ($arg eq '-s') {
$do_status = 0;
} elsif ($arg eq '-f') {
($commitlog) && die("Too many '-f' args\n");
$commitlog = shift @ARGV;
} else {
($donefiles) && die("Too many arguments! Check usage.\n");
$donefiles = 1;
@files = split(/ /, $arg);
}
}
($mailto) || die("No -m mail recipient specified\n");
# for now, the first "file" is the repository directory being committed,
# relative to the $CVSROOT location
#
@path = split('/', $files[0]);
# XXX there are some ugly assumptions in here about module names and
# XXX directories relative to the $CVSROOT location -- really should
# XXX read $CVSROOT/CVSROOT/modules, but that's not so easy to do, since
# XXX we have to parse it backwards.
#
if ($modulename eq "") {
$modulename = $path[0]; # I.e. the module name == top-level dir
}
if ($#path == 0) {
$dir = ".";
} else {
$dir = join('/', @path);
}
$dir = $dir . "/";
if ($debug) {
print STDERR "module - ", $modulename, "\n";
print STDERR "dir - ", $dir, "\n";
print STDERR "path - ", join(":", @path), "\n";
print STDERR "files - ", join(":", @files), "\n";
print STDERR "id - ", $id, "\n";
}
# Check for a new directory first. This appears with files set as follows:
#
# files[0] - "path/name/newdir"
# files[1] - "-"
# files[2] - "New"
# files[3] - "directory"
#
if ($files[2] =~ /New/ && $files[3] =~ /directory/) {
local(@text);
@text = ();
push(@text, &build_header());
push(@text, "");
push(@text, $files[0]);
push(@text, "");
while (<STDIN>) {
chop; # Drop the newline
push(@text, $_);
}
&mail_notification($mailto, @text);
exit 0;
}
# Check for an import command. This appears with files set as follows:
#
# files[0] - "path/name"
# files[1] - "-"
# files[2] - "Imported"
# files[3] - "sources"
#
if ($files[2] =~ /Imported/ && $files[3] =~ /sources/) {
local(@text);
@text = ();
push(@text, &build_header());
push(@text, "");
push(@text, $files[0]);
push(@text, "");
while (<STDIN>) {
chop; # Drop the newline
push(@text, $_);
}
&mail_notification($mailto, @text);
exit 0;
}
# Iterate over the body of the message collecting information.
#
while (<STDIN>) {
chop; # Drop the newline
if (/^In directory/) {
push(@log_lines, $_);
push(@log_lines, "");
next;
}
if (/^Modified Files/) { $state = $STATE_CHANGED; next; }
if (/^Added Files/) { $state = $STATE_ADDED; next; }
if (/^Removed Files/) { $state = $STATE_REMOVED; next; }
if (/^Log Message/) { $state = $STATE_LOG; next; }
s/^[ \t\n]+//; # delete leading whitespace
s/[ \t\n]+$//; # delete trailing whitespace
if ($state == $STATE_CHANGED) { push(@changed_files, split); }
if ($state == $STATE_ADDED) { push(@added_files, split); }
if ($state == $STATE_REMOVED) { push(@removed_files, split); }
if ($state == $STATE_LOG) { push(@log_lines, $_); }
}
# Strip leading and trailing blank lines from the log message. Also
# compress multiple blank lines in the body of the message down to a
# single blank line.
#
while ($#log_lines > -1) {
last if ($log_lines[0] ne "");
shift(@log_lines);
}
while ($#log_lines > -1) {
last if ($log_lines[$#log_lines] ne "");
pop(@log_lines);
}
for ($i = $#log_lines; $i > 0; $i--) {
if (($log_lines[$i - 1] eq "") && ($log_lines[$i] eq "")) {
splice(@log_lines, $i, 1);
}
}
if ($debug) {
print STDERR "Searching for log file index...";
}
# Find an index to a log file that matches this log message
#
for ($i = 0; ; $i++) {
local(@text);
last if (! -e "$LOG_FILE.$i.$id"); # the next available one
@text = &read_logfile("$LOG_FILE.$i.$id", "");
last if ($#text == -1); # nothing in this file, use it
last if (join(" ", @log_lines) eq join(" ", @text)); # it's the same log message as another
}
if ($debug) {
print STDERR " found log file at $i.$id, now writing tmp files.\n";
}
# Spit out the information gathered in this pass.
#
&append_names_to_file("$CHANGED_FILE.$i.$id", $dir, @changed_files);
&append_names_to_file("$ADDED_FILE.$i.$id", $dir, @added_files);
&append_names_to_file("$REMOVED_FILE.$i.$id", $dir, @removed_files);
&write_logfile("$LOG_FILE.$i.$id", @log_lines);
# Check whether this is the last directory. If not, quit.
#
if ($debug) {
print STDERR "Checking current dir against last dir.\n";
}
$_ = &read_line("$LAST_FILE.$id");
if ($_ ne $cvsroot . "/" . $files[0]) {
if ($debug) {
print STDERR sprintf("Current directory %s is not last directory %s.\n", $cvsroot . "/" .$files[0], $_);
}
exit 0;
}
if ($debug) {
print STDERR sprintf("Current directory %s is last directory %s -- all commits done.\n", $files[0], $_);
}
#
# End Of Commits!
#
# This is it. The commits are all finished. Lump everything together
# into a single message, fire a copy off to the mailing list, and drop
# it on the end of the Changes file.
#
#
# Produce the final compilation of the log messages
#
@text = ();
@status_txt = ();
push(@text, &build_header());
push(@text, "");
for ($i = 0; ; $i++) {
last if (! -e "$LOG_FILE.$i.$id"); # we're done them all!
@lines = &read_logfile("$CHANGED_FILE.$i.$id", "");
if ($#lines >= 0) {
push(@text, "Modified files:");
push(@text, &format_lists(@lines));
}
@lines = &read_logfile("$ADDED_FILE.$i.$id", "");
if ($#lines >= 0) {
push(@text, "Added files:");
push(@text, &format_lists(@lines));
}
@lines = &read_logfile("$REMOVED_FILE.$i.$id", "");
if ($#lines >= 0) {
push(@text, "Removed files:");
push(@text, &format_lists(@lines));
}
if ($#text >= 0) {
push(@text, "");
}
@lines = &read_logfile("$LOG_FILE.$i.$id", "\t");
if ($#lines >= 0) {
push(@text, "Log message:");
push(@text, @lines);
push(@text, "");
}
if ($do_status) {
local(@changed_files);
@changed_files = ();
push(@changed_files, &read_logfile("$CHANGED_FILE.$i.$id", ""));
push(@changed_files, &read_logfile("$ADDED_FILE.$i.$id", ""));
push(@changed_files, &read_logfile("$REMOVED_FILE.$i.$id", ""));
if ($debug) {
print STDERR "main: pre-sort changed_files = ", join(":", @changed_files), ".\n";
}
sort(@changed_files);
if ($debug) {
print STDERR "main: post-sort changed_files = ", join(":", @changed_files), ".\n";
}
foreach $dofile (@changed_files) {
if ($dofile =~ /\/$/) {
next; # ignore the silly "dir" entries
}
if ($debug) {
print STDERR "main(): doing 'cvs -nQq status -v $dofile'\n";
}
open(STATUS, "-|") || exec 'cvs', '-nQq', 'status', '-v', $dofile;
while (<STATUS>) {
chop;
push(@status_txt, $_);
}
}
}
}
# Write to the commitlog file
#
if ($commitlog) {
&write_commitlog($commitlog, @text);
}
if ($#status_txt >= 0) {
push(@text, @status_txt);
}
# Mailout the notification.
#
&mail_notification($mailto, @text);
# cleanup
#
if (! $debug) {
&cleanup_tmpfiles();
}
exit 0;

View file

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

View file

@ -1,774 +0,0 @@
Wed Nov 22 11:01:50 1995 Joshua Cowan <jcowan@hermit.reslife.okstate.edu>
* pcl-cvs.el (cvs-changelog-ours-p): use `user-full-name' if
`add-log-full-name' unbound, as not every uses the stuff in
add-log.el. Same with `add-log-mailing-address'.
(cvs-changelog-entries): change to `change-log-mode' unless
already in it.
Sun Jul 9 20:57:11 1995 Karl Fogel <kfogel@floss.cyclic.com>
* "/bin/rmdir" as default, not "/usr/local/bin/rmdir".
Fri Jun 16 15:24:34 1995 Jim Kingdon (kingdon@cyclic.com)
* pcl-cvs.elc, pcl-cvs-lucid.elc: Added.
* Makefile.in: Rename from Makefile and set srcdir.
Thu May 18 17:10:27 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
Automatically guess CVS log entries from ChangeLog contents.
* pcl-cvs.el (cvs-mode-changelog-commit): New command.
(cvs-changelog-full-paragraphs): New variable.
(cvs-changelog-name, cvs-narrow-changelog,
cvs-changelog-paragraph, cvs-changelog-subparagraph,
cvs-changelog-entry, cvs-changelog-ours-p, cvs-relative-path,
cvs-changelog-entries, cvs-changelog-insert-entries, cvs-union,
cvs-insert-changelog-entries, cvs-edit-delete-common-indentation):
New functions.
(cvs-mode-map): Bind 'C' to cvs-mode-changelog-commit.
(cvs-mode): Mention cvs-mode-changelog-commit in docstring.
Give the info files names ending in ".info".
* Makefile (INFOFILES, install_info): Change pcl-cvs to
pcl-cvs.info.
(pcl-cvs.info): Target renamed from pcl-cvs.
(DISTFILES): pcl-cvs removed; we handle the info files explicitly
in the dist-dir target.
(dist-dir): Depend on pcl-cvs.info. Distribute pcl-cvs.info*.
* pcl-cvs.texinfo: Change @setfilename appropriately.
* INSTALL: Updated.
* .cvsignore: Correctly ignore the info files.
* README: Note that pcl-cvs has been tested under 19.28, and that
the "cookie" naming conflict was resolved in 19.11.
* Makefile (pcl-cvs-lucid.elc): Changed this target from
pcl-cvs-lucid.el. That's a source file, for goodness' sake!
Tue May 9 13:56:50 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
* Change references to "Cygnus's remote CVS" to "Cyclic CVS".
Wed May 3 13:55:27 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
* pcl-cvs.el (cvs-parse-stderr): Handle colons after both
"rcsmerge" and "warning".
Fri Apr 28 22:38:14 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
* Makefile (ELFILES): Include pcl-cvs-startup.el.
(info, pcl-cvs): Call makeinfo appropriately for modern versions.
(pcl-cvs.aux): List dependency on pcl-cvs.texinfo.
(pcl-cvs.ps): New target.
(DVIPS): New variable.
(dist-dir): Renamed from dist, updated to accept DISTDIR value
passed from parent.
(DISTFILES): New varible.
(pcl-cvs.elc, pcl-cvs-lucid.elc): Add targets to elcfiles target.
Tue Apr 25 21:33:49 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
* pcl-cvs.el: (cvs-parse-stderr): Recognize "conflicts" as well as
"overlaps" before "during merge."
Thu Feb 16 12:17:20 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
* pcl-cvs.el (cvs-parse-stderr): Recognize "conflicts found in..."
messages attributed to "cvs server", as well as "cvs update".
Sat Feb 4 01:47:01 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
* pcl-cvs.el: Deal with the 'P' action, produced by remote CVS.
(cvs-parse-stdout): Treat 'P' like 'U' --- file is updated.
Tue Jan 31 23:31:39 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
* pcl-cvs.el (cvs-cvsroot-required): New variable.
(cvs-do-update): If cvs-cvsroot-required is not set, don't complain if
CVSROOT and cvs-cvsroot are both unset.
Sun Jan 22 21:22:22 1995 Jim Blandy <jimb@totoro.bio.indiana.edu>
* pcl-cvs.el (cvs-parse-stderr):
Some changes for Cygnus's Remote CVS. Treat
messages like "cvs server: Updating DIRECTORY" as we treat those like
"cvs update: Updating DIRECTORY". Ignore other messages starting with
"cvs server".
* pcl-cvs.el (cvs-parse-stderr): Re-indent.
* .cvsignore: Add ignore list for Texinfo litter.
* Makefile (lispdir): Set appropriately for totoro.
* pcl-cvs.el (cvs-program, cvs-diff-program, cvs-rmdir-program): Same.
Tue Jun 1 00:00:03 1993 Per Cederqvist (ceder@lysator.liu.se)
* Release 1.05. (This release was promised before the end of May,
but I didn't quite make it. No, I didn't fake the date above).
Mon May 31 01:32:25 1993 Per Cederqvist (ceder@lysator.liu.se)
* Removed the elib sub-directory. Users must now get the Elib
library separately.
* pcl-cvs.texinfo: Document it.
* pcl-cvs-lucid.el: A new version, supplied by Jamie Zawinsky,
added.
* pcl-cvs Id 68: Transform RCS keywords
* Makefile (pcl-cvs-$(VER)): Remove the $ signs in most files in
the distribution.
* pcl-cvs Id 76: Extra " in cvs-mode-add.
* pcl-cvs.el (cvs-mode-add): Don't add the extra level of quotes
around the log message, since it doesn't work with CVS.
* pcl-cvs Id 56: '-d <CVSROOT>' support in pcl-cvs
* pcl-cvs.el (cvs-change-cvsroot): New function.
* pcl-cvs Id 77: *cvs* isn't cleared properly
* pcl-cvs.el (cvs-do-update): Always erase the *cvs* buffer and
re-create the collection.
* pcl-cvs.el (cvs-do-update): Set mode-line-process in the *cvs*
buffer.
* pcl-cvs.el (cvs-mode): Reset mode-line-process.
* pcl-cvs Id 59: sort .cvsignore alphabetically!
* pcl-cvs.el (cvs-sort-ignore-file): New variable.
* pcl-cvs.el (cvs-mode-ignore): Use it.
* pcl-cvs.texinfo: Document it.
* pcl-cvs Id 75: Require final newline.
* pcl-cvs.el (cvs-commit-buffer-require-final-newline): New
variable.
* pcl-cvs.el (cvs-edit-done): Use it.
* pcl-cvs.texinfo: Document it.
* pcl-cvs Id 72: make clean deletes lucid-emacs.el
* dist-makefile (ELCFILES): Fixed a typo.
* pcl-cvs Id 46: "cvs remove f" "touch f" "cvs update f" -> parse err.
* pcl-cvs.el (cvs-fileinfo->type): New type: REM-EXIST.
* pcl-cvs.el (cvs-shadow-entry-p): A REMOVED that follows a
REM-EXIST is a shadow.
* pcl-cvs.el (cvs-parse-stderr): Recognize the "should be removed
and is still there" message.
* pcl-cvs.el (cvs-pp): Recognize REM-EXIST.
* pcl-cvs.el (cvs-mode-undo-local-changes): Recognize and complain
about REM-EXIST. Defensive test added: complain about unknown types.
* pcl-cvs.el (cvs-mode-add): Add an extra level of quotes around
the log message. This is apparently needed by RCVS. <This change
has been removed. --ceder>.
* pcl-cvs.el (cvs-parse-stderr): Ignore output from RCVS.
Tue Apr 27 00:48:40 1993 Per Cederqvist (ceder@lysator.liu.se)
* pcl-cvs.el (cvs-startup-message): Now a defconst instead of a
defvar.
* pcl-cvs.el (cvs-mode-commit): Add a defvar for it.
* dist-makefile (EMACS): Use $(EMACS) instead of hard-coding 'emacs'.
Sat Apr 17 12:47:10 1993 Per Cederqvist (ceder@lysator.liu.se)
* Release 1.04.
* pcl-cvs.texinfo: Updated the Contributors node.
* pcl-cvs Id 58: Lucid GNU Emacs support
* pcl-cvs-lucid.el: New file, contributed by the people at Lucid.
* pcl-cvs.el: Autoload pcl-cvs-lucid if running in an Lucid GNU
Emacs.
* compile-all.el: (files-to-compile): Add pcl-cvs-lucid.
* dist-makefile (ELFILES, ELCFILES): Dito.
* pcl-cvs Id 55: cvs-diff-backup swaps old and new version.
* pcl-cvs.el (cvs-diff-backup-extractor): Old version should be
first.
* pcl-cvs.el (cvs-mode-diff-backup): Call cvs-backup-diffable
correctly.
* pcl-cvs Id 64: elib substitute
* dist-makefile (install): Warn about Elib.
* pcl-cvs.texinfo: Talk about Elib.
* pcl-cvs Id 50: Committing the *commit* buffer twice.
* pcl-cvs.el (cvs-edit-done): Report an error if cvs-commit-list
is empty, and empty it when the commit is done.
* pcl-cvs Id 56: '-d <CVSROOT>' support.
* pcl-cvs.el (cvs-cvsroot): New variable.
* pcl-cvs.el (cvs-do-update, all callers of cvs-execute-list): Use
it everywhere CVS is called, to override CVSROOT.
* pcl-cvs.texinfo (Customization): Document it.
Thu Apr 1 00:34:55 1993 Per Cederqvist (ceder@lysator.liu.se)
* pcl-cvs.el (cvs-retrieve-revision-to-tmpfile): Exit status nil
from call-process means everything was successful in some Emacs
versions.
* pcl-cvs.el (cvs-mode-map): Bind "q" to bury-buffer.
* pcl-cvs.texinfo: Document it.
Thu Mar 11 00:05:03 1993 Per Cederqvist (ceder@lysator.liu.se)
* Release 1.03-Emerge (not released).
* Makefile (pcl-cvs-$(VER)): Don't includ elib-dll-debug.el in the
distribution. (It's included as elib/dll-debug.el).
* pcl-cvs.el (cvs-mode): Document the "e" key (cvs-mode-emerge).
Tue Mar 9 00:02:57 1993 Per Cederqvist (ceder@lysator.liu.se)
* pcl-cvs.texinfo (Emerge): New node.
* pcl-cvs.el (cvs-kill-buffer-visiting): New function.
* pcl-cvs.el (cvs-mode-emerge): Handle Conflict and Merged files.
* pcl-cvs.el (cvs-retrieve-revision-to-tmpfile): Handle any revision.
* pcl-cvs.el (cvs-fileinfo-*): Store base-revision instead of
backup-file.
* pcl-cvs.el (cvs-backup-diffable): The file is only diffable if
the backup file is readable.
* pcl-cvs.el (cvs-mode-map): Bind "e" to cvs-mode-emerge instead
of cvs-mode-find-file (which is anyhow bound to "f").
Mon Mar 8 23:06:52 1993 Per Cederqvist (ceder@lysator.liu.se)
* pcl-cvs.el (cvs-mode-emerge): New function. Currently only
handles emerge of Modified files.
* pcl-cvs.el (cvs-retrieve-revision-to-tmpfile): New function.
Sun Jan 24 20:07:18 1993 Per Cederqvist (ceder@lysator.liu.se)
* elib-dll-debug.el: Moved to elib.
Mon Jan 18 00:35:59 1993 Per Cederqvist (ceder@mauritz)
* pcl-cvs.el (cvs-do-update): Added a probably unnecessary sit-for.
* Release 1.03-Elib-0.05.1 (not released).
* Elib 0.05 compatibility:
* elib-dll-debug.el, pcl-cvs-buffer.el, test-dll.el: Fix the
require strings.
* pcl-cvs.el (cvs-pp): Insert the string.
* Release 1.03-Elib-0.05 (not released).
* elib: New directory, containing the parts of elib that are
required for pcl-cvs. Changes to the files in that directory
that are present in Elib are documented in the ChangeLog of
Elib, not here.
* Makefile (pcl-cvs-$(VER)): Copy the new dir to the distribution.
* dist-makefile (ELFILES, ELCFILES): Don't include the Elib files.
Fri Jan 8 02:43:49 1993 Per Cederqvist (ceder@konrad)
* pcl-cvs.el (cvs-mode-map): Bind "e" to cvs-mode-find-file, like
in dired.
Sun Jan 3 23:25:13 1993 Per Cederqvist (ceder@konrad)
* elib-dll.el, elib-node.el, cookie.el: Moved to the elib package.
Pcl-cvs now requires elib.
Tue Dec 29 22:06:57 1992 Per Cederqvist (ceder@konrad)
* pcl-cvs.el: Tracked the latest (last?) rename of all functions
in cookie.el.
Thu Sep 24 00:29:16 1992 Per Cederqvist (ceder@robert)
* pcl-cvs.texinfo (Archives): This version is not distributed with
CVS 1.3, so don't claim that it is.
Fri Aug 21 15:17:08 1992 Per Cederqvist (ceder@maskros)
* pcl-cvs.el (cvs-parse-stderr): Fixed two "(set head" that should
be "(setq head".
Thu Aug 20 05:53:58 1992 Per Cederqvist (ceder@robin)
* cookie.el: Changes to this file is documented in the ChangeLog
of elib in the future.
Tue Aug 18 03:30:28 1992 Per Cederqvist (ceder@robin)
* pcl-cvs.el: Don't use cookie-last-tin (which no longer exists).
* cookie.el: Use prefix cookie:: for internal functions.
* cookie.el: (cookie:enter-after, cookie:enter-before,
cookie:nth-cookie): Implemented.
* cookie.el: No longer define (impl).
* cookie.el: More renames:
cookie:next-cookie -> cookie:goto-next-tin
cookie:previous-cookie -> cookie:goto-previous-tin
tin-next -> cookie:next-tin
tin-previous -> cookie:previous-tin
tin-nth -> cookie:nth-tin
tin-delete -> cookie:delete-tin
cookie:collect -> cookie:collect-cookies
cookie:tin-collect -> cookie:collect-tins
(new) -> cookie:tin-collect-cookies
(new) -> cookie:tin-collect-tins
cookie:refresh -> cookie:refresh-all
tin-invalidate-tins -> cookie:invalidate-tins
Mon Aug 17 01:39:49 1992 Per Cederqvist (ceder@robin)
* cookie.el (cookie:set-buffer-bind-dll-let*): New macro. Used in
many places instead of cookie:set-buffer-bind-dll.
* cookie.el (cookie:set-buffer-bind-dll): Renamed the macro
cookie:set-buffer to this.
* pcl-cvs.el (cvs-use-temp-buffer): Set default-directory.
Sun Aug 16 20:51:30 1992 Per Cederqvist (ceder@robin)
* pcl-cvs.el (cvs-add-sub): Fixed call to cvs-add-file-update-buffer.
Sat Aug 8 20:28:21 1992 Per Cederqvist (ceder@robin)
* Release 1.03-Cookie-II (not released).
* pcl-cvs.el (cvs-mode-diff-cvs): Don't care about the exit status
from ``cvs diff''.
* pcl-cvs.el (cvs-mode): Document cvs-mode-undo-local-changes.
* pcl-cvs.el (cvs-diffable): New function.
* pcl-cvs.el: Use the new cookie package.
* pcl-cvs.el (cvs-cookie-handle): New variable.
* pcl-cvs.el (cvs-do-update): User the new cookie:create
interface, and cookie:clear if the buffer already existed. Make
the buffer read-only.
* pcl-cvs.el (cvs-mode-next-line, cvs-mode-previous-line): New
functions (used instead of cookie:next-cookie and
cookie:previous-cookie).
* cookie.el: Major redesign. The handle that is passed to all
cookie functions is now a new datatype, and not the buffer that
the cookies resides in. This way it is possible to have more than
one set of cookies in a buffer. Things that used to be
buffer-local variables are now fields in the handle data type.
cookie-last-tin is no longer available.
* cookie.el (cookie:create): The buffer is not cleared, nor set to
be read-only.
* cookie.el (cookie:next-cookie, cookie:previous-cookie): Since
the first argument is now a handle and not a buffer, these can no
longer be called interactively. You have to write a small wrapper
about them.
* cookie.el (cookie:buffer): New function.
Tue Aug 4 03:02:25 1992 Per Cederqvist (ceder@robert)
* pcl-cvs.texinfo (Bugs): Renamed "Reporting bugs and ideas" to
"Bugs" and added a table of known bugs/FAQ:s.
Mon Aug 3 00:19:39 1992 Per Cederqvist (ceder@robert)
* pcl-cvs.el, pcl-cvs.texinfo: Big Renaming Time!
The commands that operate in the *cvs* buffer:
cvs-add-change-log-entry-other-window -> cvs-mode-add-change-log-entry-other-window
cvs-mark-all-files -> cvs-mode-mark-all-files
cvs-revert-updated-buffers -> cvs-mode-revert-updated-buffers
cvs-undo-local-changes -> cvs-mode-undo-local-changes
cvs-unmark-up -> cvs-mode-unmark-up
cvs-acknowledge -> cvs-mode-acknowledge
cvs-unmark-all-files -> cvs-mode-unmark-all-files
cvs-add -> cvs-mode-add
cvs-diff-backup -> cvs-mode-diff-backup
cvs-commit -> cvs-mode-commit
cvs-diff-cvs -> cvs-mode-diff-cvs
cvs-find-file -> cvs-mode-find-file
cvs-update-no-prompt -> cvs-mode-update-no-prompt
cvs-ignore -> cvs-mode-ignore
cvs-log -> cvs-mode-log
cvs-mark -> cvs-mode-mark
cvs-find-file-other-window -> cvs-mode-find-file-other-window
cvs-remove-file -> cvs-mode-remove-file
cvs-status -> cvs-mode-status
cvs-remove-handled -> cvs-mode-remove-handled
cvs-unmark -> cvs-mode-unmark
* pcl-cvs.el (cvs-cvs-diff-flags): Variable deleted.
* pcl-cvs.el (cvs-diff-cvs): Use cvs-diff-flags instead.
* pcl-cvs.texinfo (Customization): Update the doc.
* pcl-cvs.el (cvs-diff-cvs): Handle exit status 0 (no diffs), 1
(diffs) and other (error).
* pcl-cvs.el (cvs-execute-list): Add support for this kind of
thing.
* Revert buffers for committed files:
* pcl-cvs.el (cvs-auto-revert-after-commit): New variable.
* pcl-cvs.texinfo (Committing changes, Customization): Document
it.
* pcl-cvs.el (cvs-after-commit-function): New function.
* pcl-cvs.el (cvs-execute-list): Return the exit status or nil.
* pcl-cvs.el (cvs-edit-done, cvs-diff-cvs, cvs-remove-file,
cvs-undo-local-changes, cvs-add, cvs-status, cvs-log): Use the
exit status to generate an error message.
* pcl-cvs.el (cvs-do-update): It should be "cvs -n update -l", not
"cvs -l update -n". Put the -n and/or -l in the message that is
displayed in the *cvs* buffer during the update.
Sat Aug 1 00:55:49 1992 Per Cederqvist (ceder@robert)
* cookie.el (cookie-sort): New function.
* cookie.el (cookie-clear): Rewritten. No longer clears all local
variables.
Tue Jul 28 17:21:17 1992 Per Cederqvist (ceder@robin)
* pcl-cvs.el (cvs-parse-stderr): Try to handle the output from RCS
when it is compiled without DIFF3_BIN and a conflict occurs.
* pcl-cvs.texinfo (Getting Started): Fixed typo.
* pcl-cvs-startup.el (cvs-update-other-window): Make the autoload
be interactive.
Mon Jul 27 19:36:40 1992 Per Cederqvist (ceder@robin)
* pcl-cvs.el (cvs-revert-updated-buffers, cvs-revert-fileinfo):
New functions.
* pcl-cvs.texinfo (Reverting your buffers): Document it.
* pcl-cvs.el (cvs-fileinfo->full-path): New function.
* pcl-cvs.el (cvs-full-path): Use it.
* cookie.el (cookie-map, cookie-map-reverse): Better doc-
string. Removed the unused local variable 'result'.
* compile-all.el: Renamed elib-files to files-to-compare.
* compile-all.el (compile-pcl-cvs): Bind load-path in a let
statement instead of globally.
Thu Jul 23 19:02:41 1992 Per Cederqvist (ceder@robin)
* pcl-cvs.el (cvs-do-update): Check that CVSROOT is set.
* pcl-cvs.el (cvs-diff-cvs): Check that cvs-cvs-diff-flags is a
list.
* pcl-cvs.el (cvs-diff-backup): Check that cvs-diff-flags is a
list.
Tue Jul 21 11:27:39 1992 Per Cederqvist (ceder@robin)
* pcl-cvs.el (cvs-parse-error): Make the *cvs* buffer writeable
before trying to write the email message. Require sendmail before
trying to switch to mail-mode.
* pcl-cvs.el (cvs-do-update): Check that cvs-program exists.
* pcl-cvs.el (cvs-skip-line): Fixed bracketing error.
Mon Jul 20 10:31:51 1992 Per Cederqvist (ceder@robin)
* Release 1.03.
* pcl-cvs.el, cookie.el: Indentation fixes.
* Makefile (pcl-cvs-$(VER)): Include NEWS in the distribution.
* pcl-cvs.el (cvs-rm-program): Deleted.
* pcl-cvs.el (cvs-rmdir-program, cvs-lock-file): New variables.
* Handle lock files in a nicer way:
* pcl-cvs.el (cvs-update-filter, cvs-delete-lock,
cvs-lock-file-p): New functions.
* pcl-cvs.el (cvs-do-update, cvs-sentinel): Redirect stdout to the
temporary file, not stderr. Use cvs-update-filter.
* pcl-cvs.el (cvs-parse-update): New arguments.
* pcl-cvs.el (cvs-parse-buffer): Renamed to cvs-parse-update.
* pcl-cvs.el (cvs-stderr-file): Renamed to cvs-stdout-file.
* pcl-cvs.texinfo (Miscellaneous commands, Updating the
directory): Document cvs-delete-lock.
* pcl-cvs.el (cvs-mode): Don't reset buffer-read-only.
* pcl-cvs.el (cvs-find-file-other-window): Don't save-some-buffers.
Thu Jul 16 00:19:58 1992 Per Cederqvist (ceder@robin)
* pcl-cvs.el, test-cookie-el: Use the new names from cookie.el.
* cookie.el: Big Renaming Time!
External functions:
cookie-next -> tin-next
cookie-previous -> tin-previous
cookie-nth -> tin-nth
cookie-delete -> tin-delete
cookie-filter-tins -> tin-filter
cookie-get-selection -> tin-get-selection
cookie-start-marker -> tin-start-marker
cookie-end-marker -> tin-end-marker
cookie-invalidate-tins -> tin-invalidate-tins
cookie-collect-tins -> tin-collect
cookie-collect-cookies -> cookie-collect
Internal functions:
cookie-create-tin -> cookie-create-wrapper
cookie-tin-start-marker -> cookie-wrapper-start-marker
cookie-tin-cookie-safe -> cookie-wrapper-cookie-safe
cookie-tin-cookie -> cookie-wrapper-cookie
set-cookie-tin-start-marker -> cookie-wrapper-set-start-marker
set-cookie-tin-cookie -> cookie-wrapper-set-cookie
cookie-tin-p -> cookie-wrapper-p
cookie-create-tin-and-insert -> cookie-create-wrapper-and-insert
* pcl-cvs.el (cvs-find-file, cvs-find-file-other-window): Signal
an appropriate error message if the *cvs* buffer is empty.
* cookie.el (cookie-create): Make the buffer read-only.
* cookie.el (cookie-create-tin-and-insert, cookie-refresh,
cookie-delete-tin-internal, cookie-refresh-tin): Bind
buffer-read-only to nil while changing the contents of
the buffer.
* pcl-cvs.el (cvs-byte-compile-files): New function.
* pcl-cvs.texinfo (Miscellaneous commands): Document it.
* pcl-cvs.el (cvs-diff-ignore-marks): New variable.
* pcl-cvs.el (cvs-diff-cvs, cvs-diff-backup): Don't consider
marked files to be selected if a prefix argument is given XOR the
variable cvs-diff-ignore-marks is non-nil.
* pcl-cvs.el (cvs-get-marked): New optional argument `ignore-marks'.
* pcl-cvs.texinfo (Customization, Viewing differences): Document
this behaviour.
* pcl-cvs.el (cvs-undo-local-changes): New function.
* pcl-cvs.texinfo (Undoing changes): Document
cvs-undo-local-changes.
* pcl-cvs.el (cvs-mode-map): cvs-unmark-all-files moved from "U"
to "ESC DEL". cvs-undo-local-changes bound to "U".
* pcl-cvs.texinfo (Marking files): Document ESC DEL.
* pcl-cvs.el (cvs-skip-line): New arguments. All callers updated.
Now calls cvs-parse-error if a parse error occurs.
* pcl-cvs.el (cvs-parse-error): New function that creates a bug
report.
* pcl-cvs.el (cvs-parse-stderr, cvs-parse-stdout): New arguments.
The only caller (cvs-parse-buffer) updated. Call cvs-parse-error
in case of parse error.
* pcl-cvs.el (pcl-cvs-version): New variable.
* cookie.el (cookie-create): Kill all local variables in the buffer.
Fri Jul 10 11:17:40 1992 Per Cederqvist (ceder@robin)
* Release 1.03beta1.
Thu Jul 9 03:12:00 1992 Per Cederqvist (ceder@robin)
* pcl-cvs.el (cvs-update-running): New variable.
* pcl-cvs.el (cvs-do-update): Use it instead of the previous local
variable cvs-process (that no longer exists). Make sure that only
one `cvs update' runs at any given moment.
* pcl-cvs.el (cvs-sentinel): Reset cvs-update-running when the
update process exits.
* pcl-cvs.el (cvs-update): Switch to the *cvs* buffer.
* pcl-cvs.el (cvs-update-other-window): New function.
* pcl-cvs-startup.el (cvs-update-other-window): Added a autoload
for it.
* pcl-cvs.el (cvs-do-update): Don't pop up any buffer in a window
- let cvs-update or cvs-update-other-window handle that. Also
don't kill the *cvs* buffer, but rather insert a "Running cvs..."
message into it.
* pcl-cvs.el (cvs-parse-buffer): Don't change the window
configuration.
* pcl-cvs.el (cvs-create-fileinfo, cvs-pp, cvs-fileninfo->type):
New type for a fileinfo: MESSAGE.
* pcl-cvs.el (cvs-cvs-buffer): Deleted the variable. Use
cvs-buffer-name instead. (I no longer have any plans to allow more
than one cvs update to run at the same time - things only get
confusing). Changed all places where cvs-cvs-buffer was used.
* pcl-cvs.el: Take care of update programs (the -u option in the
modules file):
* pcl-cvs.el (cvs-update-prog-output-skip-regexp): New variable.
* pcl-cvs.el (cvs-parse-stdout): Skip output from the update
program (using cvs-update-prog-output-skip-regexp).
* pcl-cvs.texinfo (Future enhancements): Document that the
solution is not as good as it should be.
* pcl-cvs.texinfo (Customization): Document the variable.
Wed Jul 8 20:29:44 1992 Per Cederqvist (ceder@robin)
* pcl-cvs.el (cvs-do-update): Check that this-dir really exists
and is a directory, and that this-dir/CVS exists and is a
directory.
Tue Jul 7 01:02:24 1992 Per Cederqvist (ceder@robin)
* pcl-cvs.texinfo (Customization): Document TMPDIR.
* This chunk of modifications should make it possible to run
pcl-cvs on hosts that do not line-buffer stdout (such as
DECstation). They work by diverting stdout and stderr from
`cvs update' and later sorting them together.
* pcl-cvs.el (cvs-parse-stderr): Don't fail to parse conflict
data.
* pcl-cvs.el (cvs-remove-stdout-shadows, cvs-shadow-entry-p): New
functions.
* pcl-cvs.el (cvs-parse-buffer): Use it.
* pcl-cvs.el (cvs-remove-empty-directories): New function.
* pcl-cvs.el (cvs-remove-handled, cvs-parse-buffer): Use it.
* pcl-cvs.el (cvs-get-current-dir): New argument ROOT-DIR. All
calls to cvs-get-current-dir updated.
* pcl-cvs.el (cvs-do-update): Allocate a tmp file. Use cvs-shell
(typically /bin/sh) to redirect stderr from CVS to the tmp file.
* pcl-cvs.el (cvs-sentinel): Handle the tmp file. Remove it when
it is parsed.
* pcl-cvs.el (cvs-parse-buffer): New argument STDERR-BUFFER. All
calls to cvs-parse-buffer updated. Rewritten to handle the
separation of stderr and stdout.
* pcl-cvs.el (cvs-shell, cvs-stderr-file): New variables.
* pcl-cvs.el (cvs-compare-fileinfos, cvs-parse-stderr,
cvs-parse-stdout): New functions.
* pcl-cvs.el (cvs-parse-buffer): Some modifications for output
from RCS 5.6.
Tue Apr 7 09:11:27 1992 Per Cederqvist (ceder@leopold)
* Release 1.02.
* pcl-cvs.el (cvs-diff-backup, cvs-edit-done, cvs-status): Call
save-some-buffers.
* pcl-cvs.el (cvs-diff-backup-extractor): Fixed syntax error.
* Makefile, README, compile-all.el, dist-makefile, pcl-cvs.el,
pcl-cvs.texinfo (XXRELEASEXX): A magic string that is substituted
for the current release number when a distribution is made.
(Release 1.01 says that it is release 1.00).
* pcl-cvs.el (cvs-find-file): Added missing pair of parenthesis.
Mon Mar 30 14:25:26 1992 Per Cederqvist (ceder@leopold)
* Release 1.01.
* pcl-cvs.el (cvs-parse-buffer): The message when waiting for a
lock has been changed.
Sun Mar 29 05:29:57 1992 Per Cederqvist (ceder@leopold)
* Release 1.00.
* pcl-cvs.el (cvs-do-update, cvs-sentinel, cvs-parse-buffer):
Major rewrite of buffer and window selection and handling.
The *cvs* buffer is now killed whenever a new "cvs update" is
initiated. The -update buffer is replaced with the *cvs*
buffer when the update is completed.
Sat Mar 28 21:03:05 1992 Per Cederqvist (ceder@robin)
* pcl-cvs.el (cvs-delete-unused-temporary-buffers): Fixed it.
* pcl-cvs.el (cvs-auto-remove-handled): New variable.
* pcl-cvs.el (cvs-edit-done): Use it.
* pcl-cvs.texinfo (Customization, Removing handled entries):
Document it.
* pcl-cvs.el (cvs-mode): Turn of the undo feature. It really
isn't useful in a cookie buffer...
* pcl-cvs.el (cvs-edit-done): Committing a file now looks more
like diffing a file. The window handling is better.
* pcl-cvs.el (cvs-use-temp-buffer): The &optional switch is no
longer needed.
Mon Mar 23 00:20:33 1992 Per Cederqvist (ceder@robin)
* Release 0.97.
* pcl-cvs.el (default-directory): Make sure it always ends in a
slash. fileinfo->dir does NOT end in a slash, and I had forgotten
to call file-name-as-directory in various places.
* pcl-cvs.el (cvs-diff-backup-extractor): Signal an error if a
fileinfo without backup file is given.
* pcl-cvs.el (cvs-mode): Added documentation.
* pcl-cvs.el (cvs-execute-list): Fix the order of files in the
same directory.
* pcl-cvs.el (cvs-log-flags, cvs-status-flags): New variables.
* pcl-cvs.el (cvs-log, cvs-status): Use them.
* pcl-cvs.texinfo (Customization): Document them.
* pcl-cvs.el (cvs-diff-backup): Filter non-backup-diffable files
at an earlier stage, like cvs-commit does.
* pcl-cvs.el (cvs-diff-flags): New variable.
* pcl-cvs.el (cvs-diff-backup): Use it.
* pcl-cvs.texinfo (Customization): Document it.
* pcl-cvs.el (cvs-execute-single-file-list): Remove &rest before
last argument. No callers needed updating.
* pcl-cvs.el (cvs-execute-list): Remove the &rest before the last
argument (constant-args). Update all callers of cvs-execute-list
to use the new calling convention.
* pcl-cvs.el (cvs-cvs-diff-flags): Now a list of strings instead
of a string.
* pcl-cvs.texinfo (Customization): Document the change to
cvs-cvs-diff-flags.
* Release 0.96.
* pcl-cvs.el (cvs-cvs-diff-flags): New variable.
* pcl-cvs.el (cvs-diff-cvs): Use it.
* pcl-cvs.texinfo (Customization, Viewing differences): Document it.
* pcl-cvs.el (cvs-use-temp-buffe): Don't switch to the temporary
buffer. Use display-buffer and set-buffer instead. This way
cvs-log, cvs-status, cvs-diff-cvs and friends don't select the
temporary buffer. The cursor will remain in the *cvs* buffer.
Sun Mar 22 21:50:18 1992 Per Cederqvist (ceder@robin)
* pcl-cvs.el (cvs-find-file, cvs-find-file-other-window): Don't
prompt when reading in a directory in dired.
* Makefile (pcl-cvs-$(VER)): Include pcl-cvs-startup.el in the
distribution.
* dist-makefile (pcl-cvs.dvi): Don't fail even if texindex does
not exist.
* pcl-cvs.texinfo (@setchapternewpage): Changed from 'off' to 'on'.
* pcl-cvs.texinfo (Variable index): Joined into function index.
* pcl-cvs.texinfo (Key index): add a description about the key.
* pcl-cvs.texinfo: Many other small changes.
Wed Mar 18 01:58:38 1992 Per Cederqvist (ceder@leopold)
* Use GNU General Public License version 2.

View file

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

View file

@ -1,16 +0,0 @@
# $Id: Makefile,v 1.6 1995/12/11 01:27:18 peter Exp $
FILES= ChangeLog INSTALL NEWS README \
compile-all.el pcl-cvs-lucid.el pcl-cvs-startup.el \
pcl-cvs.el pcl-cvs.texinfo compile.sh
NOOBJ= noobj
EXAMPDIR= /usr/share/examples/cvs
beforeinstall:
${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 644 \
${FILES} ${DESTDIR}${EXAMPDIR}/pcl-cvs
.include "../../../Makefile.inc"
.include <bsd.prog.mk>

View file

@ -1,113 +0,0 @@
This is the NEWS file for pcl-cvs, an Elisp front-end to CVS.
User-visible changes in pcl-cvs from 1.04 to 1.05:
* Elib is no longer distributed with pcl-cvs. You must get Elib
separately, for instance from ftp.lysator.liu.se in pub/emacs.
* The Lucid Emacs support works again.
* A new function, cvs-change-cvsroot, can be used to interactively
switch between CVS repositories.
* The mode line in the *cvs* buffer now indicates when a "cvs update"
is running.
* The .cvsignore file is automatically sorted alphabetically (to
reduce the risk of conflicts when two people add different files
simultaneously). This behaviour can be turned off with
cvs-sort-ignore-file.
* A trailing newline is always added in commit log messages. This
behaviour can be turned off with
cvs-commit-buffer-require-final-newline.
* This version of pcl-cvs should work together with RCVS. I have not
tested this myself, though.
* Plus some bug fixes. (Note that the version of cookie.el that is
distributed with pcl-cvs 1.04 contains errors that affects pcl-cvs.
You should get Elib 0.07).
User-visible changes in pcl-cvs from 1.03 to 1.04:
* Support for Emerge. Hitting "e" on a file that is Modified, Merged
or in Conflict will start Emerge, an interactive file merger written
in Emacs Lisp. This requires Emerge version 4. Emerge is not
included in this package. If you can't find it anywhere else, you
can get in from ftp.lysator.liu.se in pub/emacs. This package makes
it a lot easier to resolve conflicts.
* Emacs will now automatically revert your buffers when the CVS
commands pcl-cvs issues causes the file to change. This automatic
revert never occurs if the buffer contents did not agree with the
file prior to the command.
* If you are running Lucid GNU Emacs, you will get some fonts and
mouse support. This was contributed from people at Lucid.
* The variable cvs-cvsroot can be used to select the location if the
repository. You no longer need to exit Emacs, setenv CVSROOT, and
start a new Emacs if you work with multiple repositories.
* The "q" key can be used to hide the *cvs* buffer.
* The name of the commands in the *cvs* have changed. If it was called
cvs-foo, it will now be called cvs-mode-foo. See the ChangeLog
entry from Tue Aug 4 03:02:25 1992 for a complete list of changes.
* The variable cvs-cvs-diff-flags is no longer used. Instead,
cvs-diff-flags is always used.
* Plus a lot of bug fixes.
User-visible changes in pcl-cvs from 1.02 to 1.03:
* Output from CVS to stdout and stderr is separated and parsed
independently. In that way pcl-cvs should work regardless of
whether stdout is buffered or line-buffered. Pcl-cvs should now
work with CVS 1.3 without modifications on hosts such as
DECstations.
* Pcl-cvs now fully supports RCS version 5.6 as well as 5.5.
* New functions:
+ cvs-undo-local-changes ("U") - Undo all your modifications
to a file and get the newest
version from the repository.
+ cvs-update-other-window - Similar to cvs-update.
+ cvs-byte-compile-files - Byte compile the selected files.
* cvs-update now displays the *cvs* buffer, which initially contains a
small message ("Running `cvs update' in /foo/bar/gazonk/...") until
the update is ready. The *cvs* buffer no longer pops up when the
update is ready. It often failed to pop up, due to race conditions
that are very hard to solve (and I doubt that they were at all
solvable).
* cvs-unmark-all-files is moved from "U" to "ESC DEL" to be
"compatible" with dired.
* cvs-diff ("d") and cvs-diff-backup ("b") can be configured to work
on only the file the cursor is positioned on, and ignore any marked
files. A prefix argument toggles this.
* Only one `cvs update' can be run at a time. (It was previously
possible to start more than one simultaneously, but pcl-cvs could
not really handle more than one.)
* Some rudimentary support for programs that CVS runs at update (due
to the -u switch in the modules file).
* Pcl-cvs now automatically generates a bug report if it can't parse
the output from CVS.
* The *cvs* buffer is read-only.
* Pcl-cvs now creates temporary files in $TMPDIR if that environment
variable is set (otherwise it uses /tmp).
---End of file NEWS---

View file

@ -1,29 +0,0 @@
@(#) Id: README,v 1.14 1993/05/31 22:43:36 ceder Exp
This is the readme file for pcl-cvs, release 1.05.
This release of pcl-cvs requires Elib 0.07 or later. Elib is no
longer distributed with pcl-cvs, since that caused too much confusion.
You can get Elib from ftp.lysator.liu.se in pub/emacs/elib-*.tar.?.
Pcl-cvs is a front-end to CVS version 1.3. It integrates the most
frequently used CVS commands into emacs.
There is some configuration that needs to be done in pcl-cvs.el to get
it to work. See the instructions in file INSTALL.
Full documentation is in pcl-cvs.texinfo. Since it requires makeinfo
version 2 or 3 a preformatted info file is also included (pcl-cvs.info).
If you have been using a previous version of pcl-cvs (for instance
1.02 which is distributed with CVS 1.3) you should read through the
file NEWS to see what has changed.
This release has been tested under Emacs 18.59, Emacs 19.28 and Lucid
Emacs 19.6. Emacs 19.10 unfortunately has a file named cookie.el that
collides with the cookie.el that is distributed in Elib. This
conflict was resolved in 19.11. For earlier versions, there are
instructions in Elib 0.07 for how to work around the problem.
Per Cederqvist
(updated by Jim Blandy)

View file

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

View file

@ -1,2 +0,0 @@
#! /bin/sh
emacs -batch -l compile-all.el -f compile-pcl-cvs

View file

@ -1,133 +0,0 @@
;;; Mouse and font support for PCL-CVS 1.3 running in Lucid GNU Emacs
;; @(#) Id: pcl-cvs-lucid.el,v 1.2 1993/05/31 19:37:34 ceder Exp
;; Copyright (C) 1992-1993 Free Software Foundation, Inc.
;; This file is part of GNU Emacs.
;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
;; This simply adds a menu of the common CVS commands to the menubar and to
;; the right mouse button. Clicking right moves point, and then pops up a
;; menu from which commands can be executed.
;;
;; This could stand to be a lot more clever: for example, the "Commit Changes"
;; command should only be active on files for which there is something to
;; commit. Also, some indication of which files the command applies to
;; (especially in the presence of multiple marked files) would be nice.
;;
;; Middle-click runs find-file.
(require 'pcl-cvs)
(defvar cvs-menu
'("CVS"
["Find File" cvs-mode-find-file t]
["Find File Other Window" cvs-mode-find-file-other-window t]
["Interactively Merge (emerge)" cvs-mode-emerge t]
["Diff against Repository" cvs-mode-diff-cvs t]
["Diff against Backup Version" cvs-mode-diff-backup t]
"----"
["Commit Changes to Repository" cvs-mode-commit t]
["Revert File from Repository" cvs-mode-undo-local-changes t]
["Add File to Repository" cvs-mode-add t]
["Remove File from Repository" cvs-mode-remove-file t]
["Ignore File" cvs-mode-ignore t]
["Hide File" cvs-mode-acknowledge t]
["Hide Handled Files" cvs-mode-remove-handled t]
"----"
["Add ChangeLog Entry" cvs-mode-add-change-log-entry-other-window t]
["Show CVS Log" cvs-mode-log t]
["Show CVS Status" cvs-mode-status t]
"----"
["Mark File" cvs-mode-mark t]
["Unmark File" cvs-mode-unmark t]
["Mark All Files" cvs-mode-mark-all-files t]
["Unmark All Files" cvs-mode-unmark-all-files t]
"----"
["Quit" bury-buffer t]
))
(defun cvs-menu (e)
(interactive "e")
(mouse-set-point e)
(beginning-of-line)
(or (looking-at "^[* ] ") (error "No CVS file line here"))
(popup-menu cvs-menu))
(defun cvs-mouse-find-file (e)
(interactive "e")
(mouse-set-point e)
(beginning-of-line)
(or (looking-at "^[* ] ") (error "No CVS file line here"))
(cvs-mode-find-file (point)))
(define-key cvs-mode-map 'button3 'cvs-menu)
(define-key cvs-mode-map 'button2 'cvs-mouse-find-file)
(make-face 'cvs-header-face)
(make-face 'cvs-filename-face)
(make-face 'cvs-status-face)
(or (face-differs-from-default-p 'cvs-header-face)
(copy-face 'italic 'cvs-header-face))
(or (face-differs-from-default-p 'cvs-filename-face)
(copy-face 'bold 'cvs-filename-face))
(or (face-differs-from-default-p 'cvs-status-face)
(copy-face 'bold-italic 'cvs-status-face))
(defun pcl-mode-motion-highlight-line (event)
(if (save-excursion
(let* ((window (event-window event))
(buffer (and window (window-buffer window)))
(point (and buffer (event-point event))))
(and point
(progn
(set-buffer buffer)
(goto-char point)
(beginning-of-line)
(looking-at "^[* ] ")))))
(mode-motion-highlight-line event)))
(defconst pcl-cvs-font-lock-keywords
'(("^In directory \\(.+\\)$" 1 cvs-header-face)
("^[* ] \\w+ +\\(ci\\)" 1 cvs-status-face)
("^[* ] \\(Conflict\\|Merged\\)" 1 cvs-status-face)
("^[* ] \\w+ +\\(ci +\\)?\\(.+\\)$" 2 cvs-filename-face)
)
"Patterns to highlight in the *cvs* buffer.")
(defun pcl-cvs-fontify ()
;;
;; set up line highlighting
(require 'mode-motion)
(setq mode-motion-hook 'pcl-mode-motion-highlight-line)
;;
;; set up menubar
(if (and current-menubar (not (assoc "CVS" current-menubar)))
(progn
(set-buffer-menubar (copy-sequence current-menubar))
(add-menu nil "CVS" (cdr cvs-menu))))
;;
;; fontify mousable lines
(set (make-local-variable 'font-lock-keywords) pcl-cvs-font-lock-keywords)
(font-lock-mode 1)
)
(add-hook 'cvs-mode-hook 'pcl-cvs-fontify)

View file

@ -1,14 +0,0 @@
;;; @(#) Id: pcl-cvs-startup.el,v 1.4 1993/05/31 18:40:33 ceder Exp
(autoload 'cvs-update "pcl-cvs"
"Run a 'cvs update' in the current working directory. Feed the
output to a *cvs* buffer and run cvs-mode on it.
If optional prefix argument LOCAL is non-nil, 'cvs update -l' is run."
t)
(autoload 'cvs-update-other-window "pcl-cvs"
"Run a 'cvs update' in the current working directory. Feed the
output to a *cvs* buffer, display it in the other window, and run
cvs-mode on it.
If optional prefix argument LOCAL is non-nil, 'cvs update -l' is run."
t)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,185 +0,0 @@
#! /bin/sh
#
# $Id: rcs-to-cvs.sh,v 1.2 1995/07/15 03:40:34 jimb Exp $
# Based on the CVS 1.0 checkin csh script.
# Contributed by Per Cederqvist <ceder@signum.se>.
# Rewritten in sh by David MacKenzie <djm@cygnus.com>.
#
# Copyright (c) 1989, Brian Berliner
#
# You may distribute under the terms of the GNU General Public License.
#
#############################################################################
#
# Check in sources that previously were under RCS or no source control system.
#
# The repository is the directory where the sources should be deposited.
#
# Traverses the current directory, ensuring that an
# identical directory structure exists in the repository directory. It
# then checks the files in in the following manner:
#
# 1) If the file doesn't yet exist, check it in as revision 1.1
#
# The script also is somewhat verbose in letting the user know what is
# going on. It prints a diagnostic when it creates a new file, or updates
# a file that has been modified on the trunk.
#
# Bugs: doesn't put the files in branch 1.1.1
# doesn't put in release and vendor tags
#
#############################################################################
usage="Usage: rcs-to-cvs [-v] [-m message] [-f message_file] repository"
vbose=0
message=""
message_file=/usr/tmp/checkin.$$
got_one=0
if [ $# -lt 1 ]; then
echo "$usage" >&2
exit 1
fi
while [ $# -ne 0 ]; do
case "$1" in
-v)
vbose=1
;;
-m)
shift
echo $1 > $message_file
got_one=1
;;
-f)
shift
message_file=$1
got_one=2
;;
*)
break
esac
shift
done
if [ $# -lt 1 ]; then
echo "$usage" >&2
exit 1
fi
repository=$1
shift
if [ -z "$CVSROOT" ]; then
echo "Please the environmental variable CVSROOT to the root" >&2
echo " of the tree you wish to update" >&2
exit 1
fi
if [ $got_one -eq 0 ]; then
echo "Please Edit this file to contain the RCS log information" >$message_file
echo "to be associated with this directory (please remove these lines)">>$message_file
${EDITOR-/usr/ucb/vi} $message_file
got_one=1
fi
# Ya gotta share.
umask 0
update_dir=${CVSROOT}/${repository}
[ ! -d ${update_dir} ] && mkdir $update_dir
if [ -d SCCS ]; then
echo SCCS files detected! >&2
exit 1
fi
if [ -d RCS ]; then
co RCS/*
fi
for name in * .[a-zA-Z0-9]*
do
case "$name" in
RCS | *~ | \* | .\[a-zA-Z0-9\]\* ) continue ;;
esac
echo $name
if [ $vbose -ne 0 ]; then
echo "Updating ${repository}/${name}"
fi
if [ -d "$name" ]; then
if [ ! -d "${update_dir}/${name}" ]; then
echo "WARNING: Creating new directory ${repository}/${name}"
mkdir "${update_dir}/${name}"
if [ $? -ne 0 ]; then
echo "ERROR: mkdir failed - aborting" >&2
exit 1
fi
fi
cd "$name"
if [ $? -ne 0 ]; then
echo "ERROR: Couldn\'t cd to $name - aborting" >&2
exit 1
fi
if [ $vbose -ne 0 ]; then
$0 -v -f $message_file "${repository}/${name}"
else
$0 -f $message_file "${repository}/${name}"
fi
if [ $? -ne 0 ]; then
exit 1
fi
cd ..
else # if not directory
if [ ! -f "$name" ]; then
echo "WARNING: $name is neither a regular file"
echo " nor a directory - ignored"
continue
fi
file="${update_dir}/${name},v"
comment=""
if grep -s '\$Log.*\$' "${name}"; then # If $Log keyword
myext=`echo $name | sed 's,.*\.,,'`
[ "$myext" = "$name" ] && myext=
case "$myext" in
c | csh | e | f | h | l | mac | me | mm | ms | p | r | red | s | sh | sl | cl | ml | el | tex | y | ye | yr | "" )
;;
* )
echo "For file ${file}:"
grep '\$Log.*\$' "${name}"
echo -n "Please insert a comment leader for file ${name} > "
read comment
;;
esac
fi
if [ ! -f "$file" ]; then # If not exists in repository
if [ ! -f "${update_dir}/Attic/${name},v" ]; then
echo "WARNING: Creating new file ${repository}/${name}"
if [ -f RCS/"${name}",v ]; then
echo "MSG: Copying old rcs file."
cp RCS/"${name}",v "$file"
else
if [ -n "${comment}" ]; then
rcs -q -i -c"${comment}" -t${message_file} -m'.' "$file"
fi
ci -q -u1.1 -t${message_file} -m'.' "$file"
if [ $? -ne 0 ]; then
echo "ERROR: Initial check-in of $file failed - aborting" >&2
exit 1
fi
fi
else
file="${update_dir}/Attic/${name},v"
echo "WARNING: IGNORED: ${repository}/Attic/${name}"
continue
fi
else # File existed
echo "ERROR: File exists in repository: Ignored: $file"
continue
fi
fi
done
[ $got_one -eq 1 ] && rm -f $message_file
exit 0

View file

@ -1,592 +0,0 @@
#! /bin/sh
# RCS to ChangeLog generator
# Generate a change log prefix from RCS files and the ChangeLog (if any).
# Output the new prefix to standard output.
# You can edit this prefix by hand, and then prepend it to ChangeLog.
# Ignore log entries that start with `#'.
# Clump together log entries that start with `{topic} ',
# where `topic' contains neither white space nor `}'.
# Author: Paul Eggert <eggert@twinsun.com>
# $Id: rcs2log.sh,v 1.2 1995/07/28 19:48:45 eggert Exp $
# Copyright 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to
# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
tab=' '
nl='
'
# Parse options.
# defaults
: ${AWK=awk}
: ${TMPDIR=/tmp}
hostname= # name of local host (if empty, will deduce it later)
indent=8 # indent of log line
length=79 # suggested max width of log line
logins= # login names for people we know fullnames and mailaddrs of
loginFullnameMailaddrs= # login<tab>fullname<tab>mailaddr triplets
recursive= # t if we want recursive rlog
rlog_options= # options to pass to rlog
tabwidth=8 # width of horizontal tab
while :
do
case $1 in
-i) indent=${2?}; shift;;
-h) hostname=${2?}; shift;;
-l) length=${2?}; shift;;
-[nu]) # -n is obsolescent; it is replaced by -u.
case $1 in
-n) case ${2?}${3?}${4?} in
*"$tab"* | *"$nl"*)
echo >&2 "$0: -n '$2' '$3' '$4': tabs, newlines not allowed"
exit 1
esac
loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2$tab$3$tab$4
shift; shift; shift;;
-u)
# If $2 is not tab-separated, use colon for separator.
case ${2?} in
*"$nl"*)
echo >&2 "$0: -u '$2': newlines not allowed"
exit 1;;
*"$tab"*)
t=$tab;;
*)
t=:
esac
case $2 in
*"$t"*"$t"*"$t"*)
echo >&2 "$0: -u '$2': too many fields"
exit 1;;
*"$t"*"$t"*)
;;
*)
echo >&2 "$0: -u '$2': not enough fields"
exit 1
esac
loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2
shift
esac
logins=$logins$nl$login
;;
-r) rlog_options=$rlog_options$nl${2?}; shift;;
-R) recursive=t;;
-t) tabwidth=${2?}; shift;;
-*) echo >&2 "$0: usage: $0 [options] [file ...]
Options:
[-h hostname] [-i indent] [-l length] [-R] [-r rlog_option]
[-t tabwidth] [-u 'login<TAB>fullname<TAB>mailaddr']..."
exit 1;;
*) break
esac
shift
done
month_data='
m[0]="Jan"; m[1]="Feb"; m[2]="Mar"
m[3]="Apr"; m[4]="May"; m[5]="Jun"
m[6]="Jul"; m[7]="Aug"; m[8]="Sep"
m[9]="Oct"; m[10]="Nov"; m[11]="Dec"
# days in non-leap year thus far, indexed by month (0-12)
mo[0]=0; mo[1]=31; mo[2]=59; mo[3]=90
mo[4]=120; mo[5]=151; mo[6]=181; mo[7]=212
mo[8]=243; mo[9]=273; mo[10]=304; mo[11]=334
mo[12]=365
'
# Put rlog output into $rlogout.
# If no rlog options are given,
# log the revisions checked in since the first ChangeLog entry.
case $rlog_options in
'')
date=1970
if test -s ChangeLog
then
# Add 1 to seconds to avoid duplicating most recent log.
e='
/^... ... [ 0-9][0-9] [ 0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9]+ /{
'"$month_data"'
year = $5
for (i=0; i<=11; i++) if (m[i] == $2) break
dd = $3
hh = substr($0,12,2)
mm = substr($0,15,2)
ss = substr($0,18,2)
ss++
if (ss == 60) {
ss = 0
mm++
if (mm == 60) {
mm = 0
hh++
if (hh == 24) {
hh = 0
dd++
monthdays = mo[i+1] - mo[i]
if (i == 1 && year%4 == 0 && (year%100 != 0 || year%400 == 0)) monthdays++
if (dd == monthdays + 1) {
dd = 1
i++
if (i == 12) {
i = 0
year++
}
}
}
}
}
# Output comma instead of space to avoid CVS 1.5 bug.
printf "%d/%02d/%02d,%02d:%02d:%02d\n", year,i+1,dd,hh,mm,ss
exit
}
'
d=`$AWK "$e" <ChangeLog` || exit
case $d in
?*) date=$d
esac
fi
datearg="-d>$date"
esac
# If CVS is in use, examine its repository, not the normal RCS files.
if test ! -f CVS/Repository
then
rlog=rlog
repository=
else
rlog='cvs log'
repository=`sed 1q <CVS/Repository` || exit
test ! -f CVS/Root || CVSROOT=`cat <CVS/Root` || exit
case $CVSROOT in
*:/*)
# remote repository
;;
*)
# local repository
case $repository in
/*) ;;
*) repository=${CVSROOT?}/$repository
esac
if test ! -d "$repository"
then
echo >&2 "$0: $repository: bad repository (see CVS/Repository)"
exit 1
fi
esac
fi
# With no arguments, examine all files under the RCS directory.
case $# in
0)
case $repository in
'')
oldIFS=$IFS
IFS=$nl
case $recursive in
t)
RCSdirs=`find . -name RCS -type d -print`
filesFromRCSfiles='s|,v$||; s|/RCS/|/|; s|^\./||'
files=`
{
case $RCSdirs in
?*) find $RCSdirs -type f -print
esac
find . -name '*,v' -print
} |
sort -u |
sed "$filesFromRCSfiles"
`;;
*)
files=
for file in RCS/.* RCS/* .*,v *,v
do
case $file in
RCS/. | RCS/..) continue;;
RCS/.\* | RCS/\* | .\*,v | \*,v) test -f "$file" || continue
esac
files=$files$nl$file
done
case $files in
'') exit 0
esac
esac
set x $files
shift
IFS=$oldIFS
esac
esac
llogout=$TMPDIR/rcs2log$$l
rlogout=$TMPDIR/rcs2log$$r
trap exit 1 2 13 15
trap "rm -f $llogout $rlogout; exit 1" 0
case $rlog_options in
?*) $rlog $rlog_options ${1+"$@"} >$rlogout;;
'') $rlog "$datearg" ${1+"$@"} >$rlogout
esac || exit
# Get the full name of each author the logs mention, and set initialize_fullname
# to awk code that initializes the `fullname' awk associative array.
# Warning: foreign authors (i.e. not known in the passwd file) are mishandled;
# you have to fix the resulting output by hand.
initialize_fullname=
initialize_mailaddr=
case $loginFullnameMailaddrs in
?*)
case $loginFullnameMailaddrs in
*\"* | *\\*)
sed 's/["\\]/\\&/g' >$llogout <<EOF || exit
$loginFullnameMailaddrs
EOF
loginFullnameMailaddrs=`cat $llogout`
esac
oldIFS=$IFS
IFS=$nl
for loginFullnameMailaddr in $loginFullnameMailaddrs
do
case $loginFullnameMailaddr in
*"$tab"*) IFS=$tab;;
*) IFS=:
esac
set x $loginFullnameMailaddr
login=$2
fullname=$3
mailaddr=$4
initialize_fullname="$initialize_fullname
fullname[\"$login\"] = \"$fullname\""
initialize_mailaddr="$initialize_mailaddr
mailaddr[\"$login\"] = \"$mailaddr\""
done
IFS=$oldIFS
esac
case $llogout in
?*) sort -u -o $llogout <<EOF || exit
$logins
EOF
esac
output_authors='/^date: / {
if ($2 ~ /^[0-9]*[-\/][0-9][0-9][-\/][0-9][0-9]$/ && $3 ~ /^[0-9][0-9]:[0-9][0-9]:[0-9][0-9][-+0-9:]*;$/ && $4 == "author:" && $5 ~ /^[^;]*;$/) {
print substr($5, 1, length($5)-1)
}
}'
authors=`
$AWK "$output_authors" <$rlogout |
case $llogout in
'') sort -u;;
?*) sort -u | comm -23 - $llogout
esac
`
case $authors in
?*)
cat >$llogout <<EOF || exit
$authors
EOF
initialize_author_script='s/["\\]/\\&/g; s/.*/author[\"&\"] = 1/'
initialize_author=`sed -e "$initialize_author_script" <$llogout`
awkscript='
BEGIN {
alphabet = "abcdefghijklmnopqrstuvwxyz"
ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
'"$initialize_author"'
}
{
if (author[$1]) {
fullname = $5
if (fullname ~ /[0-9]+-[^(]*\([0-9]+\)$/) {
# Remove the junk from fullnames like "0000-Admin(0000)".
fullname = substr(fullname, index(fullname, "-") + 1)
fullname = substr(fullname, 1, index(fullname, "(") - 1)
}
if (fullname ~ /,[^ ]/) {
# Some sites put comma-separated junk after the fullname.
# Remove it, but leave "Bill Gates, Jr" alone.
fullname = substr(fullname, 1, index(fullname, ",") - 1)
}
abbr = index(fullname, "&")
if (abbr) {
a = substr($1, 1, 1)
A = a
i = index(alphabet, a)
if (i) A = substr(ALPHABET, i, 1)
fullname = substr(fullname, 1, abbr-1) A substr($1, 2) substr(fullname, abbr+1)
}
# Quote quotes and backslashes properly in full names.
# Do not use gsub; traditional awk lacks it.
quoted = ""
rest = fullname
for (;;) {
p = index(rest, "\\")
q = index(rest, "\"")
if (p) {
if (q && q<p) p = q
} else {
if (!q) break
p = q
}
quoted = quoted substr(rest, 1, p-1) "\\" substr(rest, p, 1)
rest = substr(rest, p+1)
}
printf "fullname[\"%s\"] = \"%s%s\"\n", $1, quoted, rest
author[$1] = 0
}
}
'
initialize_fullname=`
(cat /etc/passwd; ypmatch $authors passwd) 2>/dev/null |
$AWK -F: "$awkscript"
`$initialize_fullname
esac
# Function to print a single log line.
# We don't use awk functions, to stay compatible with old awk versions.
# `Log' is the log message (with \n replaced by \r).
# `files' contains the affected files.
printlogline='{
# Following the GNU coding standards, rewrite
# * file: (function): comment
# to
# * file (function): comment
if (Log ~ /^\([^)]*\): /) {
i = index(Log, ")")
files = files " " substr(Log, 1, i)
Log = substr(Log, i+3)
}
# If "label: comment" is too long, break the line after the ":".
sep = " "
if ('"$length"' <= '"$indent"' + 1 + length(files) + index(Log, CR)) sep = "\n" indent_string
# Print the label.
printf "%s*%s:", indent_string, files
# Print each line of the log, transliterating \r to \n.
while ((i = index(Log, CR)) != 0) {
logline = substr(Log, 1, i-1)
if (logline ~ /[^'"$tab"' ]/) {
printf "%s%s\n", sep, logline
} else {
print ""
}
sep = indent_string
Log = substr(Log, i+1)
}
}'
case $hostname in
'')
hostname=`(
hostname || uname -n || uuname -l || cat /etc/whoami
) 2>/dev/null` || {
echo >&2 "$0: cannot deduce hostname"
exit 1
}
esac
# Process the rlog output, generating ChangeLog style entries.
# First, reformat the rlog output so that each line contains one log entry.
# Transliterate \n to \r so that multiline entries fit on a single line.
# Discard irrelevant rlog output.
$AWK <$rlogout '
BEGIN { repository = "'"$repository"'" }
/^RCS file:/ {
if (repository != "") {
filename = $3
if (substr(filename, 1, length(repository) + 1) == repository "/") {
filename = substr(filename, length(repository) + 2)
}
if (filename ~ /,v$/) {
filename = substr(filename, 1, length(filename) - 2)
}
}
}
/^Working file:/ { if (repository == "") filename = $3 }
/^date: /, /^(-----------*|===========*)$/ {
if ($0 ~ /^branches: /) { next }
if ($0 ~ /^date: [0-9][- +\/0-9:]*;/) {
date = $2
if (date ~ /-/) {
# An ISO format date. Replace all "-"s with "/"s.
newdate = ""
while ((i = index(date, "-")) != 0) {
newdate = newdate substr(date, 1, i-1) "/"
date = substr(date, i+1)
}
date = newdate date
}
# Ignore any time zone; ChangeLog has no room for it.
time = substr($3, 1, 8)
author = substr($5, 1, length($5)-1)
printf "%s %s %s %s %c", filename, date, time, author, 13
next
}
if ($0 ~ /^(-----------*|===========*)$/) { print ""; next }
printf "%s%c", $0, 13
}
' |
# Now each line is of the form
# FILENAME YYYY/MM/DD HH:MM:SS AUTHOR \rLOG
# where \r stands for a carriage return,
# and each line of the log is terminated by \r instead of \n.
# Sort the log entries, first by date+time (in reverse order),
# then by author, then by log entry, and finally by file name (just in case).
sort +1 -3r +3 +0 |
# Finally, reformat the sorted log entries.
$AWK '
BEGIN {
# Some awk variants do not understand "\r" or "\013", so we have to
# put a carriage return directly in the file.
CR=" " # <-- There is a single CR between the " chars here.
# Initialize the fullname and mailaddr associative arrays.
'"$initialize_fullname"'
'"$initialize_mailaddr"'
# Initialize indent string.
indent_string = ""
i = '"$indent"'
if (0 < '"$tabwidth"')
for (; '"$tabwidth"' <= i; i -= '"$tabwidth"')
indent_string = indent_string "\t"
while (1 <= i--)
indent_string = indent_string " "
# Set up date conversion tables.
# RCS uses a nice, clean, sortable format,
# but ChangeLog wants the traditional, ugly ctime format.
# January 1, 0 AD (Gregorian) was Saturday = 6
EPOCH_WEEKDAY = 6
# Of course, there was no 0 AD, but the algorithm works anyway.
w[0]="Sun"; w[1]="Mon"; w[2]="Tue"; w[3]="Wed"
w[4]="Thu"; w[5]="Fri"; w[6]="Sat"
'"$month_data"'
}
{
newlog = substr($0, 1 + index($0, CR))
# Ignore log entries prefixed by "#".
if (newlog ~ /^#/) { next }
if (Log != newlog || date != $2 || author != $4) {
# The previous log and this log differ.
# Print the old log.
if (date != "") '"$printlogline"'
# Logs that begin with "{clumpname} " should be grouped together,
# and the clumpname should be removed.
# Extract the new clumpname from the log header,
# and use it to decide whether to output a blank line.
newclumpname = ""
sep = "\n"
if (date == "") sep = ""
if (newlog ~ /^\{[^'"$tab"' }]*}['"$tab"' ]/) {
i = index(newlog, "}")
newclumpname = substr(newlog, 1, i)
while (substr(newlog, i+1) ~ /^['"$tab"' ]/) i++
newlog = substr(newlog, i+1)
if (clumpname == newclumpname) sep = ""
}
printf sep
clumpname = newclumpname
# Get ready for the next log.
Log = newlog
if (files != "")
for (i in filesknown)
filesknown[i] = 0
files = ""
}
if (date != $2 || author != $4) {
# The previous date+author and this date+author differ.
# Print the new one.
date = $2
author = $4
# Convert nice RCS date like "1992/01/03 00:03:44"
# into ugly ctime date like "Fri Jan 3 00:03:44 1992".
# Calculate day of week from Gregorian calendar.
i = index($2, "/")
year = substr($2, 1, i-1) + 0
monthday = substr($2, i+1)
i = index(monthday, "/")
month = substr(monthday, 1, i-1) + 0
day = substr(monthday, i+1) + 0
leap = 0
if (2 < month && year%4 == 0 && (year%100 != 0 || year%400 == 0)) leap = 1
days_since_Sunday_before_epoch = EPOCH_WEEKDAY + year * 365 + int((year + 3) / 4) - int((year + 99) / 100) + int((year + 399) / 400) + mo[month-1] + leap + day - 1
# Print "date fullname (email address)".
# Get fullname and email address from associative arrays;
# default to author and author@hostname if not in arrays.
if (fullname[author])
auth = fullname[author]
else
auth = author
printf "%s %s %2d %s %d %s ", w[days_since_Sunday_before_epoch%7], m[month-1], day, $3, year, auth
if (mailaddr[author])
printf "<%s>\n\n", mailaddr[author]
else
printf "<%s@%s>\n\n", author, "'"$hostname"'"
}
if (! filesknown[$1]) {
filesknown[$1] = 1
if (files == "") files = " " $1
else files = files ", " $1
}
}
END {
# Print the last log.
if (date != "") {
'"$printlogline"'
printf "\n"
}
}
' &&
# Exit successfully.
exec rm -f $llogout $rlogout

View file

@ -1,143 +0,0 @@
#! /bin/sh
#
#
# OrigId: rcs2sccs,v 1.12 90/10/04 20:52:23 kenc Exp Locker: kenc
# $Id: rcs2sccs.sh,v 1.1 1995/07/10 02:26:45 kfogel Exp $
############################################################
# Error checking
#
if [ ! -d SCCS ] ; then
mkdir SCCS
fi
logfile=/tmp/rcs2sccs_$$_log
rm -f $logfile
tmpfile=/tmp/rcs2sccs_$$_tmp
rm -f $tmpfile
emptyfile=/tmp/rcs2sccs_$$_empty
echo -n "" > $emptyfile
initialfile=/tmp/rcs2sccs_$$_init
echo "Initial revision" > $initialfile
sedfile=/tmp/rcs2sccs_$$_sed
rm -f $sedfile
revfile=/tmp/rcs2sccs_$$_rev
rm -f $revfile
commentfile=/tmp/rcs2sccs_$$_comment
rm -f $commentfile
# create the sed script
cat > $sedfile << EOF
s,;Id;,%Z%%M% %I% %E%,g
s,;SunId;,%Z%%M% %I% %E%,g
s,;RCSfile;,%M%,g
s,;Revision;,%I%,g
s,;Date;,%E%,g
s,;Id:.*;,%Z%%M% %I% %E%,g
s,;SunId:.*;,%Z%%M% %I% %E%,g
s,;RCSfile:.*;,%M%,g
s,;Revision:.*;,%I%,g
s,;Date:.*;,%E%,g
EOF
sed -e 's/;/\\$/g' $sedfile > $tmpfile
cp $tmpfile $sedfile
############################################################
# Loop over every RCS file in RCS dir
#
for vfile in *,v; do
# get rid of the ",v" at the end of the name
file=`echo $vfile | sed -e 's/,v$//'`
# work on each rev of that file in ascending order
firsttime=1
rlog $file | grep "^revision [0-9][0-9]*\." | awk '{print $2}' | sed -e 's/\./ /g' | sort -n -u +0 +1 +2 +3 +4 +5 +6 +7 +8 | sed -e 's/ /./g' > $revfile
for rev in `cat $revfile`; do
if [ $? != 0 ]; then
echo ERROR - revision
exit
fi
# get file into current dir and get stats
date=`rlog -r$rev $file | grep "^date: " | awk '{print $2; exit}' | sed -e 's/^19//'`
time=`rlog -r$rev $file | grep "^date: " | awk '{print $3; exit}' | sed -e 's/;//'`
author=`rlog -r$rev $file | grep "^date: " | awk '{print $5; exit}' | sed -e 's/;//'`
date="$date $time"
echo ""
rlog -r$rev $file | sed -e '/^branches: /d' -e '1,/^date: /d' -e '/^===========/d' -e 's/$/\\/' | awk '{if ((total += length($0) + 1) < 510) print $0}' > $commentfile
echo "==> file $file, rev=$rev, date=$date, author=$author"
rm -f $file
co -r$rev $file >> $logfile 2>&1
if [ $? != 0 ]; then
echo ERROR - co
exit
fi
echo checked out of RCS
# add SCCS keywords in place of RCS keywords
sed -f $sedfile $file > $tmpfile
if [ $? != 0 ]; then
echo ERROR - sed
exit
fi
echo performed keyword substitutions
rm -f $file
cp $tmpfile $file
# check file into SCCS
if [ "$firsttime" = "1" ]; then
firsttime=0
echo about to do sccs admin
echo sccs admin -n -i$file $file < $commentfile
sccs admin -n -i$file $file < $commentfile >> $logfile 2>&1
if [ $? != 0 ]; then
echo ERROR - sccs admin
exit
fi
echo initial rev checked into SCCS
else
case $rev in
*.*.*.*)
brev=`echo $rev | sed -e 's/\.[0-9]*$//'`
sccs admin -fb $file 2>>$logfile
echo sccs get -e -p -r$brev $file
sccs get -e -p -r$brev $file >/dev/null 2>>$logfile
;;
*)
echo sccs get -e -p $file
sccs get -e -p $file >/dev/null 2>> $logfile
;;
esac
if [ $? != 0 ]; then
echo ERROR - sccs get
exit
fi
sccs delta $file < $commentfile >> $logfile 2>&1
if [ $? != 0 ]; then
echo ERROR - sccs delta -r$rev $file
exit
fi
echo checked into SCCS
fi
sed -e "s;^d D $rev ../../.. ..:..:.. [^ ][^ ]*;d D $rev $date $author;" SCCS/s.$file > $tmpfile
rm -f SCCS/s.$file
cp $tmpfile SCCS/s.$file
chmod 444 SCCS/s.$file
sccs admin -z $file
if [ $? != 0 ]; then
echo ERROR - sccs admin -z
exit
fi
done
rm -f $file
done
############################################################
# Clean up
#
echo cleaning up...
rm -f $tmpfile $emptyfile $initialfile $sedfile $commentfile
echo ===================================================
echo " Conversion Completed Successfully"
echo ===================================================
rm -f *,v

View file

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

View file

@ -1,277 +0,0 @@
#! xCSH_PATHx -f
#
# Sccs2rcs is a script to convert an existing SCCS
# history into an RCS history without losing any of
# the information contained therein.
# It has been tested under the following OS's:
# SunOS 3.5, 4.0.3, 4.1
# Ultrix-32 2.0, 3.1
#
# Things to note:
# + It will NOT delete or alter your ./SCCS history under any circumstances.
#
# + Run in a directory where ./SCCS exists and where you can
# create ./RCS
#
# + /usr/local/bin is put in front of the default path.
# (SCCS under Ultrix is set-uid sccs, bad bad bad, so
# /usr/local/bin/sccs here fixes that)
#
# + Date, time, author, comments, branches, are all preserved.
#
# + If a command fails somewhere in the middle, it bombs with
# a message -- remove what it's done so far and try again.
# "rm -rf RCS; sccs unedit `sccs tell`; sccs clean"
# There is no recovery and exit is far from graceful.
# If a particular module is hanging you up, consider
# doing it separately; move it from the current area so that
# the next run will have a better chance or working.
# Also (for the brave only) you might consider hacking
# the s-file for simpler problems: I've successfully changed
# the date of a delta to be in sync, then run "sccs admin -z"
# on the thing.
#
# + After everything finishes, ./SCCS will be moved to ./old-SCCS.
#
# This file may be copied, processed, hacked, mutilated, and
# even destroyed as long as you don't tell anyone you wrote it.
#
# Ken Cox
# Viewlogic Systems, Inc.
# kenstir@viewlogic.com
# ...!harvard!cg-atla!viewlog!kenstir
#
# Various hacks made by Brian Berliner before inclusion in CVS contrib area.
#
# $Id: sccs2rcs.csh,v 1.1 1995/07/10 02:26:48 kfogel 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

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,10 @@
# $Id: Makefile,v 1.12 1995/12/11 02:22:27 peter Exp $
# $Id: Makefile,v 1.13 1995/12/11 04:24:02 peter Exp $
.include "${.CURDIR}/../Makefile.inc"
.PATH: ${CVSDIR}/src
.PATH: ${CVSDIR}/lib
.PATH: ${CVSDIR}/man
PROG= cvs
MAN1= cvs.1
@ -10,11 +16,12 @@ SRCS= add.c admin.c checkin.c checkout.c classify.c client.c commit.c \
release.c remove.c repos.c root.c rtag.c server.c status.c tag.c \
update.c vers_ts.c wrapper.c
CFLAGS+= -I${.CURDIR}/../lib -DHAVE_CONFIG_H
SRCS+= subr.c error.c filesubr.c version.c myndbm.c fileattr.c watch.c run.c \
hash.c edit.c mkmodules.c scramble.c
DPADD+= ${LIBCVS} ${LIBGNUREGEX} ${LIBMD}
LDADD+= -lcvs -lgnuregex -lmd
CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../lib -I${CVSDIR}/src -I${CVSDIR}/lib -DHAVE_CONFIG_H
DPADD+= ${LIBCVS} ${LIBGNUREGEX} ${LIBMD} ${LIBCRYPT}
LDADD+= -lcvs -lgnuregex -lmd -lcrypt
.include "../../Makefile.inc"
.include <bsd.prog.mk>

View file

@ -1,60 +0,0 @@
wishlist - Tue Nov 2 15:22:58 PST 1993
* bcopy -> memcpy & friends.
** done 12/18/93
* remove static buffers.
* replace list & node cache with recursive obstacks, (xmalloc,
getnode, getlist)
* check all io functions for error return codes. also check all
system calls.
* error check mkdir.
---
Old notes...
* All sizing limits are gone. The rest of these items were incidental
in that effort.
* login name from history was duplicated. taught existing routine to
cache and use that instead. Also add routines to cache uid, pid,
etc.
* ign strings were never freed. Now they are.
* there was a printf("... %s ...", cp) vs *cp bug in history.c. Now
fixed.
* The environment variables TMPDIR, HOME, and LOGNAME were not
honored. Now they are.
* extra line inserted by do_editor() is gone. Then obviated. Editor
is now called exactly once per checkin.
* revised editor behaviour. Never use /dev/tty. If the editor
session fails, we haven't yet done anything. Therefor the user can
safely rerun cvs and we should just fail. Also use the editor for
initial log messages on added files. Also omit the confirmation
when adding directories. Adding directories will require an
explicit "commit" step soon. Make it possible to prevent null login
messages using #define REQUIRE_LOG_MESSAGES
* prototypes for all callbacks.
* all callbacks get ref pointers.
* do_recursion/start_recursion now use recusion_frame's rather than a
list of a lot of pointers and global variables.
* corrected types on status_dirproc().
* CONFIRM_DIRECTORY_ADDS
* re_comp was innappropriate in a few places. I've eliminated it.
* FORCE_MESSAGE_ON_ADD
* So I built a regression test. Let's call it a sanity check to be
less ambitious. It exposed that cvs is difficult to call from
scripts.

View file

@ -1,48 +0,0 @@
WHAT THE "DEATH SUPPORT" FEATURES DO:
(this really should be in the main manual, but noone has gotten around
to updating it).
CVS with death support can record when a file is active, or alive, and
when it is removed, or dead. With this facility you can record the
history of a file, including the fact that at some point in its life
the file was removed and then later added.
First, the following now works as expected:
touch foo
cvs add foo ; cvs ci -m "added" foo
rm foo
cvs rm foo ; cvs ci -m "removed" foo
touch foo
cvs add foo ; cvs ci -m "resurrected" foo
Second, files can now be added or removed in a branch and later merged
into the trunk.
cvs update -A
touch a b c
cvs add a b c ; cvs ci -m "added" a b c
cvs tag -b branchtag
cvs update -r branchtag
touch d ; cvs add d
rm a ; cvs rm a
cvs ci -m "added d, removed a"
cvs update -A
cvs update -jbranchtag
Added and removed files may also be merged between branches.
Files removed in the trunk may be merged into branches.
Files added on the trunk are a special case. They cannot be merged
into a branch. Instead, simply branch the file by hand.
I also extended the "cvs update -j" semantic slightly. Like before,
if you use two -j options, the changes made between the first and the
second will be merged into your working files. This has not changed.
If you use only one -j option, it is used as the second -j option.
The first is assumed to be the greatest common ancestor revision
between the revision specified by the -j and the BASE revision of your
working file.

View file

@ -1,539 +0,0 @@
/*
* 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.4 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"
#include "save-cwd.h"
#ifndef lint
static const char rcsid[] = "$CVSid: @(#)add.c 1.55 94/10/22 $";
USE(rcsid);
#endif
static int add_directory PROTO((char *repository, char *dir));
static int build_entry PROTO((char *repository, char *user, char *options,
char *message, List * entries, char *tag));
static const char *const 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 = NULL;
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);
wrap_setup ();
/* parse args */
optind = 1;
while ((c = getopt (argc, argv, "k:m:")) != -1)
{
switch (c)
{
case 'k':
if (options)
free (options);
options = RCS_check_kflag (optarg);
break;
case 'm':
message = xstrdup (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);
#ifdef CLIENT_SUPPORT
if (client_active)
{
int i;
start_server ();
ign_setup ();
if (options) send_arg(options);
option_with_arg ("-m", message);
for (i = 0; i < argc; ++i)
/* FIXME: Does this erroneously call Create_Admin in error
conditions which are only detected once the server gets its
hands on things? */
if (isdir (argv[i]))
{
char *tag;
char *date;
char *rcsdir = xmalloc (strlen (repository)
+ strlen (argv[i]) + 10);
/* before we do anything else, see if we have any
per-directory tags */
ParseTag (&tag, &date);
sprintf (rcsdir, "%s/%s", repository, argv[i]);
Create_Admin (argv[i], argv[i], rcsdir, tag, date);
if (tag)
free (tag);
if (date)
free (date);
free (rcsdir);
}
send_files (argc, argv, 0, 0);
if (fprintf (to_server, "add\n") < 0)
error (1, errno, "writing to server");
return get_responses_and_close ();
}
#endif
entries = Entries_Open (0);
/* walk the arg list adding files/dirs */
for (i = 0; i < argc; i++)
{
int begin_err = err;
int begin_added_files = added_files;
user = argv[i];
strip_trailing_slashes (user);
if (strchr (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) || wrap_name_has (user, WRAP_TOCVS))
{
/*
* 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, vers->tag) != 0)
err++;
else
{
added_files++;
if (!quiet)
{
#ifdef DEATH_SUPPORT
if (vers->tag)
error (0, 0, "\
scheduling %s `%s' for addition on branch `%s'",
(wrap_name_has (user, WRAP_TOCVS)
? "wrapper"
: "file"),
user, vers->tag);
else
#endif /* DEATH_SUPPORT */
error (0, 0, "scheduling %s `%s' for addition",
(wrap_name_has (user, WRAP_TOCVS)
? "wrapper"
: "file"),
user);
}
}
}
}
#ifdef DEATH_SUPPORT
else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
{
if (isdir (user) && !wrap_name_has (user, WRAP_TOCVS))
{
error (0, 0, "the directory `%s' cannot be added because a file of the", user);
error (1, 0, "same name already exists in the repository.");
}
else
{
if (vers->tag)
error (0, 0, "file `%s' will be added on branch `%s' from version %s",
user, vers->tag, vers->vn_rcs);
else
error (0, 0, "version %s of `%s' will be resurrected",
vers->vn_rcs, user);
Register (entries, user, "0", vers->ts_user, NULL,
vers->tag, NULL, NULL);
++added_files;
}
}
#endif /* DEATH_SUPPORT */
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, vers->ts_conflict);
free (tmp);
/* XXX - bugs here; this really resurrect the head */
/* Note that this depends on the Register above actually
having written Entries, or else it won't really
check the file out. */
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)
&& !wrap_name_has (user, WRAP_TOCVS))
{
err += add_directory (repository, user);
continue;
}
#ifdef SERVER_SUPPORT
if (server_active && begin_added_files != added_files)
server_checked_in (user, ".", repository);
#endif
}
if (added_files)
error (0, 0, "use 'cvs commit' to add %s permanently",
(added_files == 1) ? "this file" : "these files");
Entries_Close (entries);
if (message)
free (message);
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 rcsdir[PATH_MAX];
struct saved_cwd cwd;
char message[PATH_MAX + 100];
char *tag, *date;
if (strchr (dir, '/') != NULL)
{
error (0, 0,
"directory %s not added; must be a direct sub-directory", dir);
return (1);
}
if (strcmp (dir, CVSADM) == 0)
{
error (0, 0, "cannot add a `%s' directory", CVSADM);
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 (save_cwd (&cwd))
return (1);
if (chdir (dir) < 0)
{
error (0, errno, "cannot chdir to %s", dir);
return (1);
}
#ifdef SERVER_SUPPORT
if (!server_active && isfile (CVSADM))
#else
if (isfile (CVSADM))
#endif
{
error (0, 0, "%s/%s already exists", dir, CVSADM);
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;
Node *p;
List *ulist;
#if 0
char line[MAXLINELEN];
(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;
}
#endif
omask = umask (cvsumask);
if (CVS_MKDIR (rcsdir, 0777) < 0)
{
error (0, errno, "cannot mkdir %s", rcsdir);
(void) umask (omask);
goto out;
}
(void) umask (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);
}
#ifdef SERVER_SUPPORT
if (!server_active)
Create_Admin (".", dir, rcsdir, tag, date);
#else
Create_Admin (".", dir, rcsdir, tag, date);
#endif
if (tag)
free (tag);
if (date)
free (date);
(void) printf ("%s", message);
out:
if (restore_cwd (&cwd, NULL))
exit (1);
free_cwd (&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, tag)
char *repository;
char *user;
char *options;
char *message;
List *entries;
char *tag;
{
char fname[PATH_MAX];
char line[MAXLINELEN];
FILE *fp;
#ifndef DEATH_SUPPORT
/* when using the rcs death support, this case is not a problem. */
/*
* 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);
}
#endif /* no DEATH_SUPPORT */
if (noexec)
return (0);
/*
* 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
* ,t file, but who cares).
*/
(void) sprintf (line, "Initial %s", user);
Register (entries, user, "0", line, options, tag, (char *) 0, (char *) 0);
return (0);
}

View file

@ -1,179 +0,0 @@
/*
* 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.4 kit.
*
* Administration
*
* For now, this is basically a front end for rcs. All options are passed
* directly on.
*/
#include "cvs.h"
#ifdef CVS_ADMIN_GROUP
#include <grp.h>
#endif
#ifndef lint
static const char rcsid[] = "$CVSid: @(#)admin.c 1.20 94/09/30 $";
USE(rcsid);
#endif
static Dtype admin_dirproc PROTO((char *dir, char *repos, char *update_dir));
static int admin_fileproc PROTO((char *file, char *update_dir,
char *repository, List *entries,
List *srcfiles));
static const char *const 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;
#ifdef CVS_ADMIN_GROUP
struct group *grp;
#endif
if (argc <= 1)
usage (admin_usage);
#ifdef CVS_ADMIN_GROUP
grp = getgrnam(CVS_ADMIN_GROUP);
/* skip usage right check if group CVS_ADMIN_GROUP does not exist */
if (grp != NULL)
{
char *me = getcaller();
char **grnam = grp->gr_mem;
int denied = 1;
while (*grnam)
{
if (strcmp(*grnam, me) == 0)
{
denied = 0;
break;
}
grnam++;
}
if (denied)
error (1, 0, "usage is restricted to members of the group %s",
CVS_ADMIN_GROUP);
}
#endif
wrap_setup ();
/* 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);
#ifdef CLIENT_SUPPORT
if (client_active)
{
int i;
/* We're the client side. Fire up the remote server. */
start_server ();
ign_setup ();
for (i = 0; i <= ac; ++i) /* XXX send -ko too with i = 0 */
send_arg (av[i]);
#if 0
/* FIXME: We shouldn't have to send current files, but I'm not sure
whether it works. So send the files --
it's slower but it works. */
send_file_names (argc, argv);
#else
send_files (argc, argv, 0, 0);
#endif
if (fprintf (to_server, "admin\n") < 0)
error (1, errno, "writing to server");
return get_responses_and_close ();
}
#endif /* CLIENT_SUPPORT */
/* start the recursion processor */
err = start_recursion (admin_fileproc, (FILESDONEPROC) NULL, admin_dirproc,
(DIRLEAVEPROC) NULL, argc, argv, 0,
W_LOCAL, 0, 1, (char *) NULL, 1, 0);
return (err);
}
/*
* Called to run "rcs" on a particular file.
*/
/* ARGSUSED */
static int
admin_fileproc (file, update_dir, repository, entries, srcfiles)
char *file;
char *update_dir;
char *repository;
List *entries;
List *srcfiles;
{
Vers_TS *vers;
char *version;
char **argv;
int argc;
int retcode = 0;
vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL,
file, 0, 0, entries, srcfiles);
version = vers->vn_user;
if (version == NULL)
return (0);
else if (strcmp (version, "0") == 0)
{
error (0, 0, "cannot admin newly added file `%s'", file);
return (0);
}
run_setup ("%s%s", Rcsbin, RCS);
for (argc = ac, argv = av; argc; argc--, argv++)
run_arg (*argv);
run_arg (vers->srcfile->path);
if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
{
if (!quiet)
error (0, retcode == -1 ? errno : 0,
"%s failed for `%s'", RCS, file);
return (1);
}
return (0);
}
/*
* Print a warm fuzzy message
*/
/* ARGSUSED */
static Dtype
admin_dirproc (dir, repos, update_dir)
char *dir;
char *repos;
char *update_dir;
{
if (!quiet)
error (0, 0, "Administrating %s", update_dir);
return (R_PROCESS);
}

View file

@ -1,204 +0,0 @@
/*
* 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.4 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 const char rcsid[] = "$CVSid: @(#)checkin.c 1.48 94/10/07 $";
USE(rcsid);
#endif
int
Checkin (type, file, update_dir, repository,
rcs, rev, tag, options, message, entries)
int type;
char *file;
char *update_dir;
char *repository;
char *rcs;
char *rev;
char *tag;
char *options;
char *message;
List *entries;
{
char fname[PATH_MAX];
Vers_TS *vers;
int set_time;
char *fullname;
char *tocvsPath = NULL;
fullname = xmalloc (strlen (update_dir) + strlen (file) + 10);
if (update_dir[0] == '\0')
strcpy (fullname, file);
else
sprintf (fullname, "%s/%s", update_dir, file);
(void) printf ("Checking in %s;\n", fullname);
(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.
*/
tocvsPath = wrap_tocvs_process_file (fullname);
if (!noexec)
{
if (tocvsPath)
{
copy_file (tocvsPath, fname);
if (unlink_file_dir (file) < 0)
if (! existence_error (errno))
error (1, errno, "cannot remove %s", file);
copy_file (tocvsPath, file);
}
else
{
copy_file (file, fname);
}
}
run_setup ("%s%s -f %s%s", Rcsbin, RCS_CI,
rev ? "-r" : "", rev ? rev : "");
run_args ("-m%s", make_message_rcslegal (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.
*/
if (strcmp (options, "-V4") == 0) /* upgrade to V5 now */
options[0] = '\0';
run_setup ("%s%s -q %s %s%s", Rcsbin, RCS_CO, options,
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);
/* the time was correct, so leave it alone */
set_time = 0;
}
else
{
if (unlink_file (fname) < 0)
error (0, errno, "cannot remove %s", fname);
/* sync up with the time from the RCS file */
set_time = 1;
}
wrap_fromcvs_process_file (file);
/*
* If we want read-only files, muck the permissions here, before
* getting the file time-stamp.
*/
if (cvswrite == FALSE)
xchmod (file, 0);
#ifndef DEATH_SUPPORT
/* With death_support, files added with tags go into branches immediately. */
/* for added files with symbolic tags, need to add the tag too */
if (type == 'A' && tag && !isdigit (*tag))
{
(void) RCS_settag(rcs, tag, rev);
}
#endif /* No DEATH_SUPPORT */
/* re-register with the new data */
vers = Version_TS (repository, (char *) NULL, tag, (char *) NULL,
file, 1, set_time, 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, (char *) 0);
history_write (type, (char *) 0, vers->vn_rcs, file, repository);
freevers_ts (&vers);
if (tocvsPath)
if (unlink_file_dir (tocvsPath) < 0)
error (0, errno, "cannot remove %s", tocvsPath);
break;
case -1: /* fork failed */
if (tocvsPath)
if (unlink_file_dir (tocvsPath) < 0)
error (0, errno, "cannot remove %s", tocvsPath);
if (!noexec)
error (1, errno, "could not check in %s -- fork failed",
fullname);
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 (tocvsPath)
if (unlink_file_dir (tocvsPath) < 0)
error (0, errno, "cannot remove %s", tocvsPath);
if (!noexec)
{
rename_file (fname, file);
error (0, 0, "could not check in %s", fullname);
}
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)
{
(void) RCS_unlock (rcs, NULL, 1);
}
#ifdef SERVER_SUPPORT
if (server_active)
{
if (set_time)
/* Need to update the checked out file on the client side. */
server_updated (file, update_dir, repository, SERVER_UPDATED,
NULL, NULL);
else
server_checked_in (file, update_dir, repository);
}
#endif
return (0);
}

View file

@ -1,874 +0,0 @@
/*
* 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.4 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 const char rcsid[] = "$CVSid: @(#)checkout.c 1.78 94/10/07 $";
USE(rcsid);
#endif
static char *findslash PROTO((char *start, char *p));
static int build_dirs_and_chdir PROTO((char *dir, char *prepath, char *realdir,
int sticky));
static int checkout_proc PROTO((int *pargc, char **argv, char *where,
char *mwhere, char *mfile, int shorten,
int local_specified, char *omodule,
char *msg));
static int safe_location PROTO((void));
static const char *const checkout_usage[] =
{
"Usage:\n %s %s [-ANPcflnps] [-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-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-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 const char *const export_usage[] =
{
"Usage: %s %s [-NPfln] [-r rev | -D date] [-d dir] [-k kopt] module...\n",
"\t-N\tDon't shorten module paths if -d specified.\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-r rev\tCheck out revision or tag.\n",
"\t-D date\tCheck out revisions as of date.\n",
"\t-d dir\tCheck out into dir instead of module name.\n",
"\t-k kopt\tUse RCS kopt -k option on checkout.\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;
{
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;
const char *const *valid_usage;
enum mtype m_type;
/*
* 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 default (like -kv) and takes care to remove the CVS
* directory when it has done its duty
*/
if (strcmp (command_name, "export") == 0)
{
m_type = EXPORT;
valid_options = "Nnk:d:flRQqr:D:";
valid_usage = export_usage;
}
else
{
m_type = CHECKOUT;
valid_options = "ANnk:d:flRpQqcsr:D:j:P";
valid_usage = checkout_usage;
}
if (argc == -1)
usage (valid_usage);
ign_setup ();
wrap_setup ();
optind = 1;
while ((c = 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':
case 'q':
#ifdef SERVER_SUPPORT
/* The CVS 1.5 client sends these options (in addition to
Global_option requests), so we must ignore them. */
if (!server_active)
#endif
error (1, 0,
"-q or -Q must be specified before \"%s\"",
command_name);
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);
/*
* mhy 950615: -kv doesn't work for binaries with RCS keywords.
* Instead use the default provided in the RCS file (-ko for binaries).
*/
#if 0
if (!options)
options = RCS_check_kflag ("v");/* -kv is default */
#endif
}
if (!safe_location()) {
error(1, 0, "Cannot check out files into the repository itself");
}
#ifdef CLIENT_SUPPORT
if (client_active)
{
int expand_modules;
start_server ();
ign_setup ();
/* We have to expand names here because the "expand-modules"
directive to the server has the side-effect of having the
server send the check-in and update programs for the
various modules/dirs requested. If we turn this off and
simply request the names of the modules and directories (as
below in !expand_modules), those files (CVS/Checking.prog
or CVS/Update.prog) don't get created. Grrr. */
expand_modules = (!cat && !status && !pipeout
&& supported_request ("expand-modules"));
if (expand_modules)
{
/* This is done here because we need to read responses
from the server before we send the command checkout or
export files. */
client_expand_modules (argc, argv, local);
}
if (!run_module_prog) send_arg ("-n");
if (local) send_arg ("-l");
if (pipeout) send_arg ("-p");
if (!force_tag_match) send_arg ("-f");
if (aflag)
send_arg("-A");
if (!shorten)
send_arg("-N");
if (checkout_prune_dirs && strcmp (command_name, "export") != 0)
send_arg("-P");
client_prune_dirs = checkout_prune_dirs;
if (cat)
send_arg("-c");
if (where != NULL)
{
option_with_arg ("-d", where);
}
if (status)
send_arg("-s");
if (strcmp (command_name, "export") != 0
&& options != NULL
&& options[0] != '\0')
send_arg (options);
option_with_arg ("-r", tag);
if (date)
client_senddate (date);
if (join_rev1 != NULL)
option_with_arg ("-j", join_rev1);
if (join_rev2 != NULL)
option_with_arg ("-j", join_rev2);
if (expand_modules)
{
client_send_expansions (local);
}
else
{
int i;
for (i = 0; i < argc; ++i)
send_arg (argv[i]);
client_nonexpanded_setup ();
}
if (fprintf
(to_server,
strcmp (command_name, "export") == 0 ? "export\n" : "co\n")
< 0)
error (1, errno, "writing to server");
return get_responses_and_close ();
}
#endif
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) CVS_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))
{
(void) sprintf (repository, "%s/%s/%s", CVSroot, CVSROOTADM,
CVSNULLREPOS);
if (!isfile (repository))
{
mode_t omask;
omask = umask (cvsumask);
(void) CVS_MKDIR (repository, 0777);
(void) umask (omask);
}
/* I'm not sure whether this check is redundant. */
if (!isdir (repository))
error (1, 0, "there is no repository %s", repository);
Create_Admin (".", where, 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);
#ifdef SERVER_SUPPORT
if (server_active)
server_set_entstat (preload_update_dir, repository);
#endif
}
}
}
/*
* 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 && strchr (where, '/') != NULL)
{
char *slash;
slash = strrchr (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], m_type, "Updating", checkout_proc,
where, shorten, local, run_module_prog,
(char *) NULL);
close_module (db);
return (err);
}
static int
safe_location ()
{
char current[PATH_MAX];
char hardpath[PATH_MAX+5];
int x;
x = readlink(CVSroot, hardpath, sizeof hardpath - 1);
if (x == -1)
{
strcpy(hardpath, CVSroot);
}
hardpath[x] = '\0';
getwd (current);
if (strncmp(current, hardpath, strlen(hardpath)) == 0)
{
return (0);
}
return (1);
}
/*
* 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 = strrchr (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 = strrchr (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 = strrchr (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 = strrchr (where, '/');
cp2 = strrchr (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))
{
FILE *fp;
if (!noexec && *pargc > 1)
{
/* I'm not sure whether this check is redundant. */
if (!isdir (repository))
error (1, 0, "there is no repository %s", repository);
Create_Admin (".", where, repository,
(char *) NULL, (char *) NULL);
fp = open_file (CVSADM_ENTSTAT, "w+");
if (fclose(fp) == EOF)
error(1, errno, "cannot close %s", CVSADM_ENTSTAT);
#ifdef SERVER_SUPPORT
if (server_active)
server_set_entstat (where, repository);
#endif
}
else
{
/* I'm not sure whether this check is redundant. */
if (!isdir (repository))
error (1, 0, "there is no repository %s", repository);
Create_Admin (".", where, repository, tag, date);
}
}
else
{
char *repos;
/* get the contents of the previously existing repository */
repos = Name_Repository ((char *) NULL, preload_update_dir);
if (fncmp (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 = Entries_Open (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 ? vers->vn_rcs : "0",
line, vers->options, vers->tag,
vers->date, (char *) 0);
}
freevers_ts (&vers);
}
Entries_Close (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 (p >= start && *p != '/')
p--;
if (p < 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 = strchr (cp, '/')) != NULL && (slash2 = strchr (cp2, '/')) != NULL;
cp = slash + 1, cp2 = slash2 + 1)
{
*slash = '\0';
*slash2 = '\0';
(void) CVS_MKDIR (cp, 0777);
if (chdir (cp) < 0)
{
error (0, errno, "cannot chdir to %s", cp);
return (1);
}
if (!isfile (CVSADM) && strcmp (command_name, "export") != 0)
{
(void) sprintf (repository, "%s/%s", prepath, path2);
/* I'm not sure whether this check is redundant. */
if (!isdir (repository))
error (1, 0, "there is no repository %s", repository);
Create_Admin (".", cp, 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);
#ifdef SERVER_SUPPORT
if (server_active)
server_set_entstat (path, repository);
#endif
}
}
*slash = '/';
*slash2 = '/';
}
(void) CVS_MKDIR (cp, 0777);
if (chdir (cp) < 0)
{
error (0, errno, "cannot chdir to %s", cp);
return (1);
}
return (0);
}

View file

@ -1,504 +0,0 @@
/*
* 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.4 kit.
*
*/
#include "cvs.h"
#ifndef lint
static const char rcsid[] = "$CVSid: @(#)classify.c 1.17 94/10/07 $";
USE(rcsid);
#endif
#ifdef SERVER_SUPPORT
static void sticky_ck PROTO((char *file, int aflag, Vers_TS * vers,
List * entries,
char *repository, char *update_dir));
#else
static void sticky_ck PROTO((char *file, int aflag, Vers_TS * vers, List * entries));
#endif
/*
* Classify the state of a file
*/
Ctype
Classify_File (file, tag, date, options, force_tag_match, aflag, repository,
entries, srcfiles, versp, update_dir, pipeout)
char *file;
char *tag;
char *date;
char *options;
int force_tag_match;
int aflag;
char *repository;
List *entries;
List *srcfiles;
Vers_TS **versp;
char *update_dir;
int pipeout;
{
Vers_TS *vers;
Ctype ret;
char *fullname;
fullname = xmalloc (strlen (update_dir) + strlen (file) + 10);
if (update_dir[0] == '\0')
strcpy (fullname, file);
else
sprintf (fullname, "%s/%s", update_dir, file);
/* 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", fullname);
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",
fullname);
ret = T_UNKNOWN;
}
}
#ifdef DEATH_SUPPORT
else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
{
if (vers->ts_user == NULL)
/*
* Logically seems to me this should be T_UPTODATE.
* But the joining code in update.c seems to expect
* T_CHECKOUT, and that is what has traditionally been
* returned for this case.
*/
ret = T_CHECKOUT;
else
{
error (0, 0, "use `cvs add' to create an entry for %s",
fullname);
ret = T_UNKNOWN;
}
}
#endif
else
{
/* there is an rcs file */
if (vers->ts_user == NULL)
{
/* There is no user file; needs checkout */
ret = T_CHECKOUT;
}
else
{
if (pipeout)
{
/*
* The user file doesn't necessarily have anything
* to do with this.
*/
ret = T_CHECKOUT;
}
/*
* 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
*/
else if (No_Difference (file, vers, entries,
repository, update_dir))
{
/* the files were different so it is a conflict */
if (!really_quiet)
error (0, 0, "move away %s; it is in the way",
fullname);
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", fullname);
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;
#ifdef DEATH_SUPPORT
else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
/* we are resurrecting. */
ret = T_ADDED;
#endif /* DEATH_SUPPORT */
else
{
#ifdef DEATH_SUPPORT
if (vers->srcfile->flags & INATTIC
&& vers->srcfile->flags & VALID)
{
/* This file has been added on some branch other than
the one we are looking at. In the branch we are
looking at, the file was already valid. */
if (!really_quiet)
error (0, 0,
"conflict: %s has been added, but already exists",
fullname);
}
else
{
#endif /* DEATH_SUPPORT */
/*
* 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",
fullname);
#ifdef DEATH_SUPPORT
}
#endif
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",
fullname);
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",
fullname);
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",
fullname);
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",
fullname);
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,
repository, update_dir))
{
/* they are different -> conflict */
if (!really_quiet)
error (0, 0,
"conflict: %s is modified but no longer in the repository",
fullname);
ret = T_CONFLICT;
}
else
{
/* they weren't really different */
if (!really_quiet)
error (0, 0,
"warning: %s is not (any longer) pertinent",
fullname);
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", fullname);
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
{
#ifdef SERVER_SUPPORT
sticky_ck (file, aflag, vers, entries,
repository, update_dir);
#else
sticky_ck (file, aflag, vers, entries);
#endif
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,
repository, update_dir))
{
/*
* 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;
#ifdef SERVER_SUPPORT
sticky_ck (file, aflag, vers, entries,
repository, update_dir);
#else
sticky_ck (file, aflag, vers, entries);
#endif /* SERVER_SUPPORT */
#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", fullname);
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
*/
#ifdef SERVER_SUPPORT
if (strcmp (vers->entdata->options ?
vers->entdata->options : "", vers->options) != 0
|| (vers->srcfile != NULL
&& (vers->srcfile->flags & INATTIC) != 0))
ret = T_CHECKOUT;
else
ret = T_PATCH;
#else
ret = T_CHECKOUT;
#endif
}
else
{
if (No_Difference (file, vers, entries,
repository, update_dir))
/* really modified, needs to merge */
ret = T_NEEDS_MERGE;
#ifdef SERVER_SUPPORT
else if ((strcmp (vers->entdata->options ?
vers->entdata->options : "", vers->options)
!= 0)
|| (vers->srcfile != NULL
&& (vers->srcfile->flags & INATTIC) != 0))
/* not really modified, check it out */
ret = T_CHECKOUT;
else
ret = T_PATCH;
#else
else
/* not really modified, check it out */
ret = T_CHECKOUT;
#endif
}
}
}
/* free up the vers struct, or just return it */
if (versp != (Vers_TS **) NULL)
*versp = vers;
else
freevers_ts (&vers);
free (fullname);
/* return the status of the file */
return (ret);
}
static void
#ifdef SERVER_SUPPORT
sticky_ck (file, aflag, vers, entries, repository, update_dir)
#else
sticky_ck (file, aflag, vers, entries)
#endif
char *file;
int aflag;
Vers_TS *vers;
List *entries;
#ifdef SERVER_SUPPORT
char *repository;
char *update_dir;
#endif
{
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, vers->ts_conflict);
#ifdef SERVER_SUPPORT
if (server_active)
{
/* We need to update the entries line on the client side.
It is possible we will later update it again via
server_updated or some such, but that is OK. */
server_update_entries
(file, update_dir, repository,
strcmp (vers->ts_rcs, vers->ts_user) == 0 ?
SERVER_UPDATED : SERVER_MERGED);
}
#endif
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,163 +0,0 @@
/* Interface between the client and the rest of CVS. */
/* Stuff shared with the server. */
extern char *mode_to_string PROTO((mode_t));
extern int change_mode PROTO((char *, char *));
extern int gzip_level;
extern int filter_through_gzip PROTO((int, int, int, pid_t *));
extern int filter_through_gunzip PROTO((int, int, pid_t *));
#ifdef CLIENT_SUPPORT
/*
* Functions to perform CVS commands via the protocol. argc and argv
* are the arguments and the return value is the exit status (zero success
* nonzero failure).
*/
extern int client_commit PROTO((int argc, char **argv));
extern int client_update PROTO((int argc, char **argv));
extern int client_checkout PROTO((int argc, char **argv));
extern int client_diff PROTO((int argc, char **argv));
extern int client_log PROTO((int argc, char **argv));
extern int client_add PROTO((int argc, char **argv));
extern int client_remove PROTO((int argc, char **argv));
extern int client_status PROTO((int argc, char **argv));
extern int client_rdiff PROTO((int argc, char **argv));
extern int client_tag PROTO((int argc, char **argv));
extern int client_rtag PROTO((int argc, char **argv));
extern int client_import PROTO((int argc, char **argv));
extern int client_admin PROTO((int argc, char **argv));
extern int client_export PROTO((int argc, char **argv));
extern int client_history PROTO((int argc, char **argv));
extern int client_release PROTO((int argc, char **argv));
/*
* Flag variable for seeing whether common code is running as a client
* or to do a local operation.
*/
extern int client_active;
/* Is the -P option to checkout or update specified? */
extern int client_prune_dirs;
/* Stream to write to the server. */
extern FILE *to_server;
/* Stream to read from the server. */
extern FILE *from_server;
/* Internal functions that handle client communication to server, etc. */
int supported_request PROTO ((char *));
void option_with_arg PROTO((char *option, char *arg));
/* Get the responses and then close the connection. */
extern int get_responses_and_close PROTO((void));
extern int get_server_responses PROTO((void));
/* Start up the connection to the server on the other end. */
void
start_server PROTO((void));
/* Send the names of all the argument files to the server. */
void
send_file_names PROTO((int argc, char **argv));
/*
* Send Repository, Modified and Entry. argc and argv contain only
* the files to operate on (or empty for everything), not options.
* local is nonzero if we should not recurse (-l option). Also sends
* Argument lines for argc and argv, so should be called after options
* are sent.
*/
void
send_files PROTO((int argc, char **argv, int local, int aflag));
/*
* Like send_files but never send "Unchanged"--just send the contents of the
* file in that case. This is used to fix it if you import a directory which
* happens to have CVS directories (yes it is obscure but the testsuite tests
* it).
*/
void
send_files_contents PROTO((int argc, char **argv, int local, int aflag));
/* Send an argument to the remote server. */
void
send_arg PROTO((char *string));
/* Send a string of single-char options to the remote server, one by one. */
void
send_option_string PROTO((char *string));
#endif /* CLIENT_SUPPORT */
/*
* This structure is used to catalog the responses the client is
* prepared to see from the server.
*/
struct response
{
/* Name of the response. */
char *name;
#ifdef CLIENT_SUPPORT
/*
* Function to carry out the response. ARGS is the text of the
* command after name and, if present, a single space, have been
* stripped off. The function can scribble into ARGS if it wants.
*/
void (*func) PROTO((char *args, int len));
/*
* ok and error are special; they indicate we are at the end of the
* responses, and error indicates we should exit with nonzero
* exitstatus.
*/
enum {response_type_normal, response_type_ok, response_type_error} type;
#endif
/* Used by the server to indicate whether response is supported by
the client, as set by the Valid-responses request. */
enum {
/*
* Failure to implement this response can imply a fatal
* error. This should be set only for responses which were in the
* original version of the protocol; it should not be set for new
* responses.
*/
rs_essential,
/* Some clients might not understand this response. */
rs_optional,
/*
* Set by the server to one of the following based on what this
* client actually supports.
*/
rs_supported,
rs_not_supported
} status;
};
/* Table of responses ending in an entry with a NULL name. */
extern struct response responses[];
#ifdef CLIENT_SUPPORT
extern void client_senddate PROTO((const char *date));
extern void client_expand_modules PROTO((int argc, char **argv, int local));
extern void client_send_expansions PROTO((int local));
extern void client_nonexpanded_setup PROTO((void));
extern char **failed_patches;
extern int failed_patches_count;
extern char toplevel_wd[];
extern void client_import_setup PROTO((char *repository));
extern int client_process_import_file
PROTO((char *message, char *vfile, char *vtag,
int targc, char *targv[], char *repository));
extern void client_import_done PROTO((void));
#endif /* CLIENT_SUPPORT */

File diff suppressed because it is too large Load diff

View file

@ -1,28 +0,0 @@
#!/bin/sh
#
# short script to convert cvs repositories to support file death.
#
WORKDIR=/tmp/$$-cvs-convert
mkdir ${WORKDIR}
cd ${WORKDIR}
case $# in
1) ;;
*)
echo Usage: convert repository 2>&1
exit 1
;;
esac
attics=`find $1 -name Attic -print`
for i in ${attics} ; do
mkdir $i/SAVE
for j in $i/*,v ; do
echo $j
cp $j $i/SAVE
co -l $j
ci -f -sdead -m"recording file death" $j
done
done

View file

@ -1,144 +0,0 @@
/*
* 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.4 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 const char rcsid[] = "$CVSid: @(#)create_adm.c 1.28 94/09/23 $";
USE(rcsid);
#endif
/* update_dir includes dir as its last component. */
void
Create_Admin (dir, update_dir, repository, tag, date)
char *dir;
char *update_dir;
char *repository;
char *tag;
char *date;
{
FILE *fout;
char *cp;
char tmp[PATH_MAX];
#ifdef SERVER_SUPPORT
if (trace)
{
char wd[PATH_MAX];
getwd (wd);
fprintf (stderr, "%c-> Create_Admin (%s, %s, %s, %s, %s) in %s\n",
(server_active) ? 'S' : ' ',
dir, update_dir, repository, tag ? tag : "",
date ? date : "", wd);
}
#endif
if (noexec)
return;
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 in %s already", update_dir);
make_directory (tmp);
#ifdef CVSADM_ROOT
/* record the current cvs root for later use */
Create_Root (dir, CVSroot);
#endif /* CVSADM_ROOT */
if (dir != NULL)
(void) sprintf (tmp, "%s/%s", dir, CVSADM_REP);
else
(void) strcpy (tmp, CVSADM_REP);
fout = fopen (tmp, "w+");
if (fout == NULL)
{
if (update_dir[0] == '\0')
error (1, errno, "cannot open %s", tmp);
else
error (1, errno, "cannot open %s/%s", update_dir, CVSADM_REP);
}
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) < 0)
{
if (update_dir[0] == '\0')
error (1, errno, "write to %s failed", tmp);
else
error (1, errno, "write to %s/%s failed", update_dir, CVSADM_REP);
}
if (fclose (fout) == EOF)
{
if (update_dir[0] == '\0')
error (1, errno, "cannot close %s", tmp);
else
error (1, errno, "cannot close %s/%s", update_dir, CVSADM_REP);
}
/* now, do the Entries file */
if (dir != NULL)
(void) sprintf (tmp, "%s/%s", dir, CVSADM_ENT);
else
(void) strcpy (tmp, CVSADM_ENT);
fout = fopen (tmp, "w+");
if (fout == NULL)
{
if (update_dir[0] == '\0')
error (1, errno, "cannot open %s", tmp);
else
error (1, errno, "cannot open %s/%s", update_dir, CVSADM_ENT);
}
if (fclose (fout) == EOF)
{
if (update_dir[0] == '\0')
error (1, errno, "cannot close %s", tmp);
else
error (1, errno, "cannot close %s/%s", update_dir, CVSADM_ENT);
}
/* Create a new CVS/Tag file */
WriteTag (dir, tag, date);
#ifdef SERVER_SUPPORT
if (server_active)
server_set_sticky (update_dir, repository, tag, date);
if (trace)
{
fprintf (stderr, "%c<- Create_Admin\n",
(server_active) ? 'S' : ' ');
}
#endif
}

File diff suppressed because it is too large Load diff

View file

@ -1,367 +0,0 @@
.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/commitinfo,v
.TP
.B $CVSROOT/CVSROOT/cvsignore,v
.TP
.B $CVSROOT/CVSROOT/cvswrappers,v
.TP
.B $CVSROOT/CVSROOT/editinfo,v
.TP
.B $CVSROOT/CVSROOT/history
.TP
.B $CVSROOT/CVSROOT/loginfo,v
.TP
.B $CVSROOT/CVSROOT/modules,v
.TP
.B $CVSROOT/CVSROOT/rcsinfo,v
.TP
.B $CVSROOT/CVSROOT/taginfo,v
.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 `\|cvswrappers\|' file to record
.B cvs
wrapper commands to be used when checking files into and out of the
repository. Wrappers allow the file or directory to be processed
on the way in and out of CVS. The intended uses are many, one
possible use would be to reformat a C file before the file is checked
in, so all of the code in the repository looks the same.
.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 `\|taginfo\|' file to define programs to execute after
any
.BR tag or rtag
operation. These programs might be used to append a message to a file
listing the new tag name and the programmer who created it, or send mail
to a group of developers, or, perhaps, post a 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 ( 8 )
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\-e\fP \fIprog\fP\|' allows you to specify a program \fIprog\fP
to run whenever files in a module are exported. \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 `\|taginfo\|', the rest of the
line is a command-line template to execute.
The arguments passed to the command are, in order, the
.I tagname ,
.I operation
(i.e.
.B add
for `tag',
.B mov
for `tag -F', and
.B del
for `tag -d`),
.I repository ,
and any remaining are pairs of
.B "filename revision" .
A non-zero exit of the filter program will cause the tag to be aborted.
.SP
For `\|commitinfo\|', the rest of the line is a command-line template to
execute.
The template 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 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.

View file

@ -1,570 +0,0 @@
/* $CVSid: @(#)cvs.h 1.86 94/10/22 $ */
/*
* basic information used in all source files
*
*/
#include "config.h" /* this is stuff found via autoconf */
#include "options.h" /* these are some larger questions which
can't easily be automatically checked
for */
/* AIX requires this to be the first thing in the file. */
#ifdef __GNUC__
#define alloca __builtin_alloca
#else /* not __GNUC__ */
#if HAVE_ALLOCA_H
#include <alloca.h>
#else /* not HAVE_ALLOCA_H */
#ifdef _AIX
#pragma alloca
#else /* not _AIX */
#ifdef ALLOCA_IN_STDLIB
/* then we need do nothing */
#else
char *alloca ();
#endif /* not ALLOCA_IN_STDLIB */
#endif /* not _AIX */
#endif /* not HAVE_ALLOCA_H */
#endif /* not __GNUC__ */
/* Changed from if __STDC__ to ifdef __STDC__ because of Sun's acc compiler */
#ifdef __STDC__
#define PTR void *
#else
#define PTR char *
#endif
/* Add prototype support. */
#ifndef PROTO
#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
#define PROTO(ARGS) ARGS
#else
#define PROTO(ARGS) ()
#endif
#endif
#if __GNUC__ == 2
#define USE(var) static const char sizeof##var = sizeof(sizeof##var) + sizeof(var)
#else
#define USE(var) static const char standalone_semis_illegal_sigh
#endif
#include <stdio.h>
/* Under OS/2, <stdio.h> doesn't define popen()/pclose(). */
#ifdef USE_OWN_POPEN
#include "popen.h"
#endif
#ifdef STDC_HEADERS
#include <stdlib.h>
#else
extern void exit ();
extern char *getenv();
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
#ifdef SERVER_SUPPORT
/* If the system doesn't provide strerror, it won't be declared in
string.h. */
char *strerror ();
#endif
#include <fnmatch.h> /* This is supposed to be available on Posix systems */
#include <ctype.h>
#include <pwd.h>
#include <signal.h>
#ifdef HAVE_ERRNO_H
#include <errno.h>
#else
#ifndef errno
extern int errno;
#endif /* !errno */
#endif /* HAVE_ERRNO_H */
#include "system.h"
#include "hash.h"
#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
#include "server.h"
#include "client.h"
#endif
#ifdef AUTH_CLIENT_SUPPORT
extern int use_authenticating_server;
void connect_to_pserver();
# ifndef CVS_AUTH_PORT
# define CVS_AUTH_PORT 2401
# endif /* CVS_AUTH_PORT */
#endif /* AUTH_CLIENT_SUPPORT */
#ifdef MY_NDBM
#include "myndbm.h"
#else
#include <ndbm.h>
#endif /* MY_NDBM */
#include "regex.h"
#include "getopt.h"
#include "wait.h"
/* Define to enable alternate death support (which uses the RCS state). */
#define DEATH_STATE 1
#define DEATH_SUPPORT 1
#include "rcs.h"
/* XXX - for now this is static */
#ifndef PATH_MAX
#ifdef MAXPATHLEN
#define PATH_MAX MAXPATHLEN+2
#else
#define PATH_MAX 1024+2
#endif
#endif /* PATH_MAX */
/* just in case this implementation does not define this */
#ifndef L_tmpnam
#define L_tmpnam 50
#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.4 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_ENTLOG "CVS/Entries.Log"
#define CVSADM_ENTSTAT "CVS/Entries.Static"
#define CVSADM_REP "CVS/Repository"
#define CVSADM_ROOT "CVS/Root"
#define CVSADM_CIPROG "CVS/Checkin.prog"
#define CVSADM_UPROG "CVS/Update.prog"
#define CVSADM_TAG "CVS/Tag"
/*
* 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_TAGINFO "taginfo"
#define CVSROOTADM_EDITINFO "editinfo"
#define CVSROOTADM_HISTORY "history"
#define CVSROOTADM_IGNORE "cvsignore"
#define CVSROOTADM_CHECKOUTLIST "checkoutlist"
#define CVSROOTADM_WRAPPER "cvswrappers"
#define CVSNULLREPOS "Emptydir" /* an empty directory */
/* support for the modules file (CVSROOTADM_MODULES) */
#define CVSMODULE_OPTS "ad:i:lo:e:s:t:u:"/* options in modules file */
#define CVSMODULE_SPEC '&' /* special delimiter */
/* Other CVS file names */
/* Files go in the attic if the head main branch revision is dead,
otherwise they go in the regular repository directories. The whole
concept of having an attic is sort of a relic from before death
support but on the other hand, it probably does help the speed of
some operations (such as main branch checkouts and updates). */
#define CVSATTIC "Attic"
#define CVSLCK "#cvs.lock"
#define CVSTFL "#cvs.tfl"
#define CVSRFL "#cvs.rfl"
#define CVSWFL "#cvs.wfl"
#define CVSRFLPAT "#cvs.rfl.*" /* wildcard expr to match read locks */
#define CVSEXT_LOG ",t"
#define CVSPREFIX ",,"
#define CVSDOTIGNORE ".cvsignore"
#define CVSDOTWRAPPER ".cvswrappers"
/* 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 */
#ifndef DEVNULL
#define DEVNULL "/dev/null"
#endif
#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 EDITOR1_ENV "CVSEDITOR" /* which editor to use */
#define EDITOR2_ENV "VISUAL" /* which editor to use */
#define EDITOR3_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 */
#define WRAPPER_ENV "CVSWRAPPERS" /* name of the wrapper file */
#define CVSUMASK_ENV "CVSUMASK" /* Effective umask for repository */
/* #define CVSUMASK_DFLT Set by config.h */
/*
* 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 MAXDATELEN 50 /* max length for a date */
/* structure of a entry record */
struct entnode
{
char *user;
char *version;
char *timestamp;
char *options;
char *tag;
char *date;
char *conflict;
};
typedef struct entnode Entnode;
/* The type of request that is being done in do_module() */
enum mtype
{
CHECKOUT, TAG, PATCH, EXPORT
};
/*
* 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 */
#ifdef SERVER_SUPPORT
T_PATCH, /* P Like C, but can patch */
#endif
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 version for the rcs file
* (tag version?) */
char *vn_tag; /* the symbolic tag name */
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 *ts_conflict; /* Holds time_stamp of conflict */
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 Entries_Open() and
* Version_TS().
*/
struct stickydirtag
{
int aflag;
char *tag;
char *date;
char *options;
};
/* 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, *program_path, *command_name;
extern char *Rcsbin, *Editor, *CVSroot;
#ifdef CVSADM_ROOT
extern char *CVSADM_Root;
extern int cvsadmin_root;
#endif /* CVSADM_ROOT */
extern char *CurDir;
extern int really_quiet, quiet;
extern int use_editor;
extern int cvswrite;
extern mode_t cvsumask;
extern int trace; /* Show all commands */
extern int noexec; /* Don't modify disk anywhere */
extern int logoff; /* Don't write history entry */
extern char hostname[];
/* Externs that are included directly in the CVS sources */
int RCS_settag PROTO((const char *, const char *, const char *));
int RCS_deltag PROTO((const char *, const char *, int));
int RCS_setbranch PROTO((const char *, const char *));
int RCS_lock PROTO((const char *, const char *, int));
int RCS_unlock PROTO((const char *, const char *, int));
int RCS_merge PROTO((const char *, const char *, const char *, const char *));
#include "error.h"
DBM *open_module PROTO((void));
FILE *open_file PROTO((const char *, const char *));
List *Find_Dirs PROTO((char *repository, int which));
void Entries_Close PROTO((List *entries));
List *Entries_Open PROTO((int aflag));
char *Make_Date PROTO((char *rawdate));
char *Name_Repository PROTO((char *dir, char *update_dir));
#ifdef CVSADM_ROOT
char *Name_Root PROTO((char *dir, char *update_dir));
void Create_Root PROTO((char *dir, char *rootdir));
int same_directories PROTO((char *dir1, char *dir2));
#endif /* CVSADM_ROOT */
char *Short_Repository PROTO((char *repository));
char *gca PROTO((char *rev1, char *rev2));
char *getcaller PROTO((void));
char *time_stamp PROTO((char *file));
char *xmalloc PROTO((size_t bytes));
char *xrealloc PROTO((char *ptr, size_t bytes));
char *xstrdup PROTO((const char *str));
void strip_trailing_newlines PROTO((char *str));
int No_Difference PROTO((char *file, Vers_TS * vers, List * entries,
char *repository, char *update_dir));
typedef int (*CALLPROC) PROTO((char *repository, char *value));
int Parse_Info PROTO((char *infofile, char *repository, CALLPROC callproc, int all));
int Reader_Lock PROTO((char *xrepository));
typedef RETSIGTYPE (*SIGCLEANUPPROC) PROTO(());
int SIG_register PROTO((int sig, SIGCLEANUPPROC sigcleanup));
int Writer_Lock PROTO((List * list));
int ign_name PROTO((char *name));
int isdir PROTO((const char *file));
int isfile PROTO((const char *file));
int islink PROTO((const char *file));
int isreadable PROTO((const char *file));
int iswritable PROTO((const char *file));
int isaccessible PROTO((const char *file, const int mode));
int isabsolute PROTO((const char *filename));
char *last_component PROTO((char *path));
int joining PROTO((void));
int numdots PROTO((const char *s));
int unlink_file PROTO((const char *f));
int unlink_file_dir PROTO((const char *f));
int update PROTO((int argc, char *argv[]));
int xcmp PROTO((const char *file1, const char *file2));
int yesno PROTO((void));
void *valloc PROTO((size_t bytes));
time_t get_date PROTO((char *date, struct timeb *now));
void Create_Admin PROTO((char *dir, char *update_dir,
char *repository, char *tag, char *date));
void Lock_Cleanup PROTO((void));
void ParseTag PROTO((char **tagp, char **datep));
void Scratch_Entry PROTO((List * list, char *fname));
void WriteTag PROTO((char *dir, char *tag, char *date));
void cat_module PROTO((int status));
void check_entries PROTO((char *dir));
void close_module PROTO((DBM * db));
void copy_file PROTO((const char *from, const char *to));
void (*error_set_cleanup PROTO((void (*) (void)))) PROTO ((void));
void fperror PROTO((FILE * fp, int status, int errnum, char *message,...));
void free_names PROTO((int *pargc, char *argv[]));
void freevers_ts PROTO((Vers_TS ** versp));
void ign_add PROTO((char *ign, int hold));
void ign_add_file PROTO((char *file, int hold));
void ign_setup PROTO((void));
void ign_dir_add PROTO((char *name));
int ignore_directory PROTO((char *name));
void line2argv PROTO((int *pargc, char *argv[], char *line));
void make_directories PROTO((const char *name));
void make_directory PROTO((const char *name));
void rename_file PROTO((const char *from, const char *to));
void strip_path PROTO((char *path));
void strip_trailing_slashes PROTO((char *path));
void update_delproc PROTO((Node * p));
void usage PROTO((const char *const *cpp));
void xchmod PROTO((char *fname, int writable));
char *xgetwd PROTO((void));
int Checkin PROTO((int type, char *file, char *update_dir,
char *repository, char *rcs, char *rev,
char *tag, char *options, char *message, List *entries));
Ctype Classify_File PROTO((char *file, char *tag, char *date, char *options,
int force_tag_match, int aflag, char *repository,
List *entries, List *srcfiles, Vers_TS **versp,
char *update_dir, int pipeout));
List *Find_Names PROTO((char *repository, int which, int aflag,
List ** optentries));
void Register PROTO((List * list, char *fname, char *vn, char *ts,
char *options, char *tag, char *date, char *ts_conflict));
void Update_Logfile PROTO((char *repository, char *xmessage, char *xrevision,
FILE * xlogfp, List * xchanges));
Vers_TS *Version_TS PROTO((char *repository, char *options, char *tag,
char *date, char *user, int force_tag_match,
int set_time, List * entries, List * xfiles));
void do_editor PROTO((char *dir, char **messagep,
char *repository, List * changes));
typedef int (*CALLBACKPROC) PROTO((int *pargc, char *argv[], char *where,
char *mwhere, char *mfile, int horten, int local_specified,
char *omodule, char *msg));
typedef int (*FILEPROC) PROTO((char *file, char *update_dir, char *repository,
List * entries, List * srcfiles));
typedef int (*FILESDONEPROC) PROTO((int err, char *repository, char *update_dir));
typedef Dtype (*DIRENTPROC) PROTO((char *dir, char *repos, char *update_dir));
typedef int (*DIRLEAVEPROC) PROTO((char *dir, int err, char *update_dir));
int do_module PROTO((DBM * db, char *mname, enum mtype m_type, char *msg,
CALLBACKPROC callback_proc, char *where, int shorten,
int local_specified, int run_module_prog, char *extra_arg));
int do_recursion PROTO((FILEPROC xfileproc, FILESDONEPROC xfilesdoneproc,
DIRENTPROC xdirentproc, DIRLEAVEPROC xdirleaveproc,
Dtype xflags, int xwhich, int xaflag, int xreadlock,
int xdosrcs));
int do_update PROTO((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 PROTO((int type, char *update_dir, char *revs, char *name,
char *repository));
int start_recursion PROTO((FILEPROC fileproc, FILESDONEPROC filesdoneproc,
DIRENTPROC direntproc, DIRLEAVEPROC dirleaveproc,
int argc, char *argv[], int local, int which,
int aflag, int readlock, char *update_preload,
int dosrcs, int wd_is_repos));
void SIG_beginCrSect PROTO((void));
void SIG_endCrSect PROTO((void));
void read_cvsrc PROTO((int *argc, char ***argv));
char *make_message_rcslegal PROTO((char *message));
/* 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 */
void run_arg PROTO((const char *s));
void run_print PROTO((FILE * fp));
#ifdef HAVE_VPRINTF
void run_setup PROTO((const char *fmt,...));
void run_args PROTO((const char *fmt,...));
#else
void run_setup ();
void run_args ();
#endif
int run_exec PROTO((char *stin, char *stout, char *sterr, int flags));
/* other similar-minded stuff from run.c. */
FILE *Popen PROTO((const char *, const char *));
int piped_child PROTO((char **, int *, int *));
void close_on_exec PROTO((int));
int filter_stream_through_program PROTO((int, int, char **, pid_t *));
pid_t waitpid PROTO((pid_t, int *, int));
/* Wrappers. */
typedef enum { WRAP_MERGE, WRAP_COPY } WrapMergeMethod;
typedef enum { WRAP_TOCVS, WRAP_FROMCVS, WRAP_CONFLICT } WrapMergeHas;
void wrap_setup PROTO((void));
int wrap_name_has PROTO((const char *name,WrapMergeHas has));
char *wrap_tocvs_process_file PROTO((const char *fileName));
int wrap_merge_is_copy PROTO((const char *fileName));
char *wrap_fromcvs_process_file PROTO((const char *fileName));
/* Pathname expansion */
char *expand_path PROTO((char *name));
void wrap_add_file PROTO((const char *file,int temp));
void wrap_add PROTO((char *line,int temp));

View file

@ -1,151 +0,0 @@
/*
* Copyright (c) 1993 david d zuhn
*
* written by david d `zoo' zuhn while at Cygnus Support
*
* You may distribute under the terms of the GNU General Public License
* as specified in the README file that comes with the CVS 1.4 kit.
*
*/
#include "cvs.h"
#include "getline.h"
#ifndef lint
static const char rcsid[] = "$CVSid: @(#)cvsrc.c 1.9 94/09/30 $";
USE(rcsid);
#endif /* lint */
/* this file is to be found in the user's home directory */
#ifndef CVSRC_FILENAME
#define CVSRC_FILENAME ".cvsrc"
#endif
char cvsrc[] = CVSRC_FILENAME;
#define GROW 10
extern char *strtok ();
void
read_cvsrc (argc, argv)
int *argc;
char ***argv;
{
char *homedir;
char *homeinit;
FILE *cvsrcfile;
char *line;
int line_length;
size_t line_chars_allocated;
char *optstart;
int command_len;
int found = 0;
int i;
int new_argc;
int max_new_argv;
char **new_argv;
/* don't do anything if argc is -1, since that implies "help" mode */
if (*argc == -1)
return;
/* setup the new options list */
new_argc = 1;
max_new_argv = (*argc) + GROW;
new_argv = (char **) xmalloc (max_new_argv * sizeof (char*));
new_argv[0] = xstrdup ((*argv)[0]);
/* determine filename for ~/.cvsrc */
homedir = getenv ("HOME");
if (!homedir)
return;
homeinit = (char *) xmalloc (strlen (homedir) + strlen (cvsrc) + 10);
strcpy (homeinit, homedir);
strcat (homeinit, "/");
strcat (homeinit, cvsrc);
/* if it can't be read, there's no point to continuing */
if (!isreadable (homeinit))
{
free (homeinit);
return;
}
/* now scan the file until we find the line for the command in question */
line = NULL;
line_chars_allocated = 0;
command_len = strlen (command_name);
cvsrcfile = open_file (homeinit, "r");
while ((line_length = getline (&line, &line_chars_allocated, cvsrcfile))
>= 0)
{
/* skip over comment lines */
if (line[0] == '#')
continue;
/* stop if we match the current command */
if (!strncmp (line, command_name, command_len)
&& isspace (*(line + command_len)))
{
found = 1;
break;
}
}
fclose (cvsrcfile);
if (found)
{
/* skip over command in the options line */
optstart = strtok (line + command_len, "\t \n");
do
{
new_argv [new_argc] = xstrdup (optstart);
new_argv [new_argc+1] = NULL;
new_argc += 1;
if (new_argc >= max_new_argv)
{
char **tmp_argv;
max_new_argv += GROW;
tmp_argv = (char **) xmalloc (max_new_argv * sizeof (char*));
for (i = 0; i <= new_argc; i++)
tmp_argv[i] = new_argv[i];
free(new_argv);
new_argv = tmp_argv;
}
}
while ((optstart = strtok (NULL, "\t \n")) != NULL);
}
if (line != NULL)
free (line);
/* now copy the remaining arguments */
for (i=1; i < *argc; i++)
{
new_argv [new_argc] = (*argv)[i];
new_argc += 1;
}
*argc = new_argc;
*argv = new_argv;
free (homeinit);
return;
}

View file

@ -1,633 +0,0 @@
/*
* 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.4 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 const char rcsid[] = "$CVSid: @(#)diff.c 1.61 94/10/22 $";
USE(rcsid);
#endif
static Dtype diff_dirproc PROTO((char *dir, char *pos_repos, char *update_dir));
static int diff_filesdoneproc PROTO((int err, char *repos, char *update_dir));
static int diff_dirleaveproc PROTO((char *dir, int err, char *update_dir));
static int diff_file_nodiff PROTO((char *file, char *repository, List *entries,
List *srcfiles, Vers_TS *vers));
static int diff_fileproc PROTO((char *file, char *update_dir, char *repository,
List * entries, List * srcfiles));
static void diff_mark_errors PROTO((int err));
static char *diff_rev1, *diff_rev2;
static char *diff_date1, *diff_date2;
static char *use_rev1, *use_rev2;
#ifdef SERVER_SUPPORT
/* Revision of the user file, if it is unchanged from something in the
repository and we want to use that fact. */
static char *user_file_rev;
#endif
static char *options;
static char opts[PATH_MAX];
static int diff_errors;
static int empty_files = 0;
static const char *const diff_usage[] =
{
"Usage: %s %s [-lN] [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-N\tinclude diffs for added and removed files.\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;
int which;
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.
*/
#ifdef SERVER_SUPPORT
/* Need to be able to do this command more than once (according to
the protocol spec, even if the current client doesn't use it). */
opts[0] = '\0';
#endif
optind = 1;
while ((c = getopt (argc, argv,
"abcdefhilnpqtuw0123456789BHNQRTC: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 'N':
empty_files = 1;
break;
case '?':
default:
usage (diff_usage);
break;
}
}
argc -= optind;
argv += optind;
/* make sure options is non-null */
if (!options)
options = xstrdup ("");
#ifdef CLIENT_SUPPORT
if (client_active) {
/* We're the client side. Fire up the remote server. */
start_server ();
ign_setup ();
if (local)
send_arg("-l");
if (empty_files)
send_arg("-N");
send_option_string (opts);
if (diff_rev1)
option_with_arg ("-r", diff_rev1);
if (diff_date1)
client_senddate (diff_date1);
if (diff_rev2)
option_with_arg ("-r", diff_rev2);
if (diff_date2)
client_senddate (diff_date2);
#if 0
/* FIXME: We shouldn't have to send current files to diff two revs, but it
doesn't work yet and I haven't debugged it. So send the files --
it's slower but it works. gnu@cygnus.com Apr94 */
/* Idea: often times the changed region of a file is relatively small.
It would be cool if the client could just divide the file into 4k
blocks or whatever and send hash values for the blocks. Send hash
values for blocks aligned with the beginning of the file and the
end of the file. Then the server can tell how much of the head and
tail of the file is unchanged. Well, hash collisions will screw
things up, but MD5 has 128 bits of hash value... */
/* Send the current files unless diffing two revs from the archive */
if (diff_rev2 == NULL && diff_date2 == NULL)
send_files (argc, argv, local);
else
send_file_names (argc, argv);
#else
send_files (argc, argv, local, 0);
#endif
if (fprintf (to_server, "diff\n") < 0)
error (1, errno, "writing to server");
err = get_responses_and_close ();
free (options);
return (err);
}
#endif
which = W_LOCAL;
if (diff_rev2 != NULL || diff_date2 != NULL)
which |= W_REPOS | W_ATTIC;
wrap_setup ();
/* start the recursion processor */
err = start_recursion (diff_fileproc, diff_filesdoneproc, diff_dirproc,
diff_dirleaveproc, argc, argv, local,
which, 0, 1, (char *) NULL, 1, 0);
/* 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;
enum {
DIFF_ERROR,
DIFF_ADDED,
DIFF_REMOVED,
DIFF_NEITHER
} empty_file = DIFF_NEITHER;
char tmp[L_tmpnam+1];
char *tocvsPath;
char fname[PATH_MAX];
#ifdef SERVER_SUPPORT
user_file_rev = 0;
#endif
vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL,
file, 1, 0, entries, srcfiles);
if (diff_rev2 != NULL || diff_date2 != NULL)
{
/* Skip all the following checks regarding the user file; we're
not using it. */
}
else 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')
{
if (empty_files)
empty_file = DIFF_ADDED;
else
{
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] == '-')
{
if (empty_files)
empty_file = DIFF_REMOVED;
else
{
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);
}
#ifdef SERVER_SUPPORT
else if (!strcmp (vers->ts_user, vers->ts_rcs))
{
/* The user file matches some revision in the repository
Diff against the repository (for remote CVS, we might not
have a copy of the user file around). */
user_file_rev = vers->vn_user;
}
#endif
}
}
if (empty_file == DIFF_NEITHER && diff_file_nodiff (file, repository, entries, srcfiles, vers))
{
freevers_ts (&vers);
return (0);
}
#ifdef DEATH_SUPPORT
/* FIXME: Check whether use_rev1 and use_rev2 are dead and deal
accordingly. */
#endif
/* Output an "Index:" line for patch to use */
(void) fflush (stdout);
if (update_dir[0])
(void) printf ("Index: %s/%s\n", update_dir, file);
else
(void) printf ("Index: %s\n", file);
(void) fflush (stdout);
tocvsPath = wrap_tocvs_process_file(file);
if (tocvsPath)
{
/* Backup the current version of the file to CVS/,,filename */
sprintf(fname,"%s/%s%s",CVSADM, CVSPREFIX, file);
if (unlink_file_dir (fname) < 0)
if (! existence_error (errno))
error (1, errno, "cannot remove %s", file);
rename_file (file, fname);
/* Copy the wrapped file to the current directory then go to work */
copy_file (tocvsPath, file);
}
if (empty_file == DIFF_ADDED || empty_file == DIFF_REMOVED)
{
(void) printf ("===================================================================\nRCS file: %s\n",
file);
(void) printf ("diff -N %s\n", file);
if (empty_file == DIFF_ADDED)
{
run_setup ("%s %s %s %s", DIFF, opts, DEVNULL, file);
}
else
{
/*
* FIXME: Should be setting use_rev1 using the logic in
* diff_file_nodiff, and using that revision. This code
* is broken for "cvs diff -N -r foo".
*/
run_setup ("%s%s -p -q %s -r%s", Rcsbin, RCS_CO,
*options ? options : vers->options, vers->vn_rcs);
run_arg (vers->srcfile->path);
if (run_exec (RUN_TTY, tmpnam (tmp), RUN_TTY, RUN_REALLY) == -1)
{
(void) unlink (tmp);
error (1, errno, "fork failed during checkout of %s",
vers->srcfile->path);
}
run_setup ("%s %s %s %s", DIFF, opts, tmp, DEVNULL);
}
}
else
{
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;
}
if (tocvsPath)
{
if (unlink_file_dir (file) < 0)
if (! existence_error (errno))
error (1, errno, "cannot remove %s", file);
rename_file (fname,file);
if (unlink_file (tocvsPath) < 0)
error (1, errno, "cannot remove %s", file);
}
if (empty_file == DIFF_REMOVED)
(void) unlink (tmp);
(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
*
* Don't try to diff directories that don't exist! -- DW
*/
/* 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??? */
/* YES ... for instance dirs that don't exist!!! -- DW */
if (!isdir (dir) )
return (R_SKIP_ALL);
if (!quiet)
error (0, 0, "Diffing %s", update_dir);
return (R_PROCESS);
}
/*
* Concoct the proper exit status - done with files
*/
/* ARGSUSED */
static int
diff_filesdoneproc (err, repos, update_dir)
int err;
char *repos;
char *update_dir;
{
return (diff_errors);
}
/*
* Concoct the proper exit status - leaving directories
*/
/* 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)
{
/* Don't gripe if it doesn't exist, just ignore! */
if (! isfile (file))
/* null statement */ ;
else 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)
{
/* Don't gripe if it doesn't exist, just ignore! */
if (! isfile (file))
/* null statement */ ;
else 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 */
if (use_rev1 && use_rev2) {
return (strcmp (use_rev1, use_rev2) == 0);
} else {
error(0, 0, "No HEAD revision for file %s", file);
return (1);
}
}
#ifdef SERVER_SUPPORT
if (user_file_rev)
{
/* drop user_file_rev into first unused use_rev */
if (!use_rev1)
use_rev1 = xstrdup (user_file_rev);
else if (!use_rev2)
use_rev2 = xstrdup (user_file_rev);
/* and if not, it wasn't needed anyhow */
user_file_rev = 0;
}
/* now, see if we really need to do the diff */
if (use_rev1 && use_rev2)
{
return (strcmp (use_rev1, use_rev2) == 0);
}
#endif /* SERVER_SUPPORT */
if (use_rev1 == NULL || strcmp (use_rev1, vers->vn_user) == 0)
{
if (strcmp (vers->ts_rcs, vers->ts_user) == 0 &&
(!(*options) || strcmp (options, vers->options) == 0))
{
return (1);
}
if (use_rev1 == NULL)
use_rev1 = xstrdup (vers->vn_user);
}
/*
* with 0 or 1 -r option specified, run a quick diff to see if we
* should bother with it at all.
*/
run_setup ("%s%s -p -q %s -r%s", Rcsbin, RCS_CO,
*options ? options : vers->options, use_rev1);
run_arg (vers->srcfile->path);
switch (run_exec (RUN_TTY, tmpnam (tmp), RUN_TTY, RUN_REALLY))
{
case 0: /* everything ok */
if (xcmp (file, tmp) == 0)
{
(void) unlink (tmp);
return (1);
}
break;
case -1: /* fork failed */
(void) unlink (tmp);
error (1, errno, "fork failed during checkout of %s",
vers->srcfile->path);
default:
break;
}
(void) unlink (tmp);
return (0);
}

View file

@ -1,555 +0,0 @@
/*
* 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.4 kit.
*
* Entries file to Files file
*
* Creates the file Files containing the names that comprise the project, from
* the Entries file.
*/
#include "cvs.h"
#include "getline.h"
#ifndef lint
static const char rcsid[] = "$CVSid: @(#)entries.c 1.44 94/10/07 $";
USE(rcsid);
#endif
static Node *AddEntryNode PROTO((List * list, Entnode *entnode));
static Entnode *fgetentent PROTO((FILE *));
static int fputentent PROTO((FILE *, Entnode *));
static FILE *entfile;
static char *entfilename; /* for error messages */
/*
* Construct an Entnode
*/
Entnode *
Entnode_Create(user, vn, ts, options, tag, date, ts_conflict)
const char *user;
const char *vn;
const char *ts;
const char *options;
const char *tag;
const char *date;
const char *ts_conflict;
{
Entnode *ent;
/* Note that timestamp and options must be non-NULL */
ent = (Entnode *) xmalloc (sizeof (Entnode));
ent->user = xstrdup (user);
ent->version = xstrdup (vn);
ent->timestamp = xstrdup (ts ? ts : "");
ent->options = xstrdup (options ? options : "");
ent->tag = xstrdup (tag);
ent->date = xstrdup (date);
ent->conflict = xstrdup (ts_conflict);
return ent;
}
/*
* Destruct an Entnode
*/
void
Entnode_Destroy (ent)
Entnode *ent;
{
free (ent->user);
free (ent->version);
free (ent->timestamp);
free (ent->options);
if (ent->tag)
free (ent->tag);
if (ent->date)
free (ent->date);
if (ent->conflict)
free (ent->conflict);
free (ent);
}
/*
* Write out the line associated with a node of an entries file
*/
static int write_ent_proc PROTO ((Node *, void *));
static int
write_ent_proc (node, closure)
Node *node;
void *closure;
{
if (fputentent(entfile, (Entnode *) node->data))
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, NULL);
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);
/* now, remove the log file */
unlink_file (CVSADM_ENTLOG);
}
/*
* Removes the argument file from the Entries file if necessary.
*/
void
Scratch_Entry (list, fname)
List *list;
char *fname;
{
Node *node;
if (trace)
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> Scratch_Entry(%s)\n",
(server_active) ? 'S' : ' ', fname);
#else
(void) fprintf (stderr, "-> Scratch_Entry(%s)\n", fname);
#endif
/* hashlookup to see if it is there */
if ((node = findnode (list, fname)) != NULL)
{
delnode (node); /* delete the node */
#ifdef SERVER_SUPPORT
if (server_active)
server_scratch (fname);
#endif
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, ts_conflict)
List *list;
char *fname;
char *vn;
char *ts;
char *options;
char *tag;
char *date;
char *ts_conflict;
{
Entnode *entnode;
Node *node;
#ifdef SERVER_SUPPORT
if (server_active)
{
server_register (fname, vn, ts, options, tag, date, ts_conflict);
}
#endif
if (trace)
{
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> Register(%s, %s, %s%s%s, %s, %s %s)\n",
(server_active) ? 'S' : ' ',
fname, vn, ts ? ts : "",
ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "",
options, tag ? tag : "", date ? date : "");
#else
(void) fprintf (stderr, "-> Register(%s, %s, %s%s%s, %s, %s %s)\n",
fname, vn, ts ? ts : "",
ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "",
options, tag ? tag : "", date ? date : "");
#endif
}
entnode = Entnode_Create(fname, vn, ts, options, tag, date, ts_conflict);
node = AddEntryNode (list, entnode);
if (!noexec)
{
entfile = open_file (CVSADM_ENTLOG, "a");
write_ent_proc (node, NULL);
if (fclose (entfile) == EOF)
error (1, errno, "error closing %s", CVSADM_ENTLOG);
}
}
/*
* 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);
}
static Entnode *
fgetentent(fpin)
FILE *fpin;
{
Entnode *ent;
char *line;
size_t line_chars_allocated;
register char *cp;
char *user, *vn, *ts, *options;
char *tag_or_date, *tag, *date, *ts_conflict;
line = NULL;
line_chars_allocated = 0;
ent = NULL;
while (getline (&line, &line_chars_allocated, fpin) > 0)
{
if (line[0] != '/')
continue;
user = line + 1;
if ((cp = strchr (user, '/')) == NULL)
continue;
*cp++ = '\0';
vn = cp;
if ((cp = strchr (vn, '/')) == NULL)
continue;
*cp++ = '\0';
ts = cp;
if ((cp = strchr (ts, '/')) == NULL)
continue;
*cp++ = '\0';
options = cp;
if ((cp = strchr (options, '/')) == NULL)
continue;
*cp++ = '\0';
tag_or_date = cp;
if ((cp = strchr (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;
if ((ts_conflict = strchr (ts, '+')))
*ts_conflict++ = '\0';
/*
* XXX - Convert timestamp from old format to new format.
*
* If the timestamp doesn't match the file's current
* mtime, we'd have to generate a string that doesn't
* match anyways, so cheat and base it on the existing
* string; it doesn't have to match the same mod time.
*
* For an unmodified file, write the correct timestamp.
*/
{
struct stat sb;
if (strlen (ts) > 30 && stat (user, &sb) == 0)
{
char *c = ctime (&sb.st_mtime);
if (!strncmp (ts + 25, c, 24))
ts = time_stamp (user);
else
{
ts += 24;
ts[0] = '*';
}
}
}
ent = Entnode_Create(user, vn, ts, options, tag, date, ts_conflict);
break;
}
free (line);
return ent;
}
static int
fputentent(fp, p)
FILE *fp;
Entnode *p;
{
if (fprintf (fp, "/%s/%s/%s", p->user, p->version, p->timestamp) < 0)
return 1;
if (p->conflict)
{
if (fprintf (fp, "+%s", p->conflict) < 0)
return 1;
}
if (fprintf (fp, "/%s/", p->options) < 0)
return 1;
if (p->tag)
{
if (fprintf (fp, "T%s\n", p->tag) < 0)
return 1;
}
else if (p->date)
{
if (fprintf (fp, "D%s\n", p->date) < 0)
return 1;
}
else
{
if (fprintf (fp, "\n") < 0)
return 1;
}
return 0;
}
/*
* Read the entries file into a list, hashing on the file name.
*/
List *
Entries_Open (aflag)
int aflag;
{
List *entries;
Entnode *ent;
char *dirtag, *dirdate;
int do_rewrite = 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));
memset ((char *) sdtp, 0, 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;
}
fpin = fopen (CVSADM_ENT, "r");
if (fpin == NULL)
error (0, errno, "cannot open %s for reading", CVSADM_ENT);
else
{
while ((ent = fgetentent (fpin)) != NULL)
{
(void) AddEntryNode (entries, ent);
}
fclose (fpin);
}
fpin = fopen (CVSADM_ENTLOG, "r");
if (fpin != NULL)
{
while ((ent = fgetentent (fpin)) != NULL)
{
(void) AddEntryNode (entries, ent);
}
do_rewrite = 1;
fclose (fpin);
}
if (do_rewrite && !noexec)
write_entries (entries);
/* clean up and return */
if (fpin)
(void) fclose (fpin);
if (dirtag)
free (dirtag);
if (dirdate)
free (dirdate);
return (entries);
}
void
Entries_Close(list)
List *list;
{
if (list)
{
if (!noexec)
{
if (isfile (CVSADM_ENTLOG))
write_entries (list);
}
dellist(&list);
}
}
/*
* 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;
Entnode_Destroy(p);
}
/*
* Get an Entries file list node, initialize it, and add it to the specified
* list
*/
static Node *
AddEntryNode (list, entdata)
List *list;
Entnode *entdata;
{
Node *p;
/* was it already there? */
if ((p = findnode (list, entdata->user)) != NULL)
{
/* take it out */
delnode (p);
}
/* 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 */
/* FIXME This results in duplicated data --- the hash package shouldn't
assume that the key is dynamically allocated. The user's free proc
should be responsible for freeing the key. */
p->key = xstrdup (entdata->user);
p->data = (char *) entdata;
/* put the node into the list */
addnode (list, p);
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) < 0)
error (1, errno, "write to %s failed", tmp);
}
else
{
if (fprintf (fout, "D%s\n", date) < 0)
error (1, errno, "write to %s failed", tmp);
}
if (fclose (fout) == EOF)
error (1, errno, "cannot close %s", tmp);
}
else
if (unlink_file (tmp) < 0 && ! existence_error (errno))
error (1, errno, "cannot remove %s", tmp);
}
/*
* Parse the CVS/Tag file for the current directory.
*/
void
ParseTag (tagp, datep)
char **tagp;
char **datep;
{
FILE *fp;
if (tagp)
*tagp = (char *) NULL;
if (datep)
*datep = (char *) NULL;
fp = fopen (CVSADM_TAG, "r");
if (fp)
{
char *line;
int line_length;
size_t line_chars_allocated;
line = NULL;
line_chars_allocated = 0;
if ((line_length = getline (&line, &line_chars_allocated, fp)) > 0)
{
/* Remove any trailing newline. */
if (line[line_length - 1] == '\n')
line[--line_length] = '\0';
if (*line == 'T' && tagp)
*tagp = xstrdup (line + 1);
else if (*line == 'D' && datep)
*datep = xstrdup (line + 1);
}
(void) fclose (fp);
free (line);
}
}

View file

@ -1,139 +0,0 @@
/* expand_path.c -- expand environmental variables in passed in string
The main routine is expand_pathname, it is the routine
that handles the '~' character in four forms:
~name
~name/
~/
~
and handles environment variables contained within the pathname
which are defined by:
c is some character
${var_name} var_name is the name of the environ variable
$var_name var_name ends with a non ascii character
char *expand_pathname(char *name)
This routine will expand the pathname to account for ~
and $ characters as described above.If an error occurs, NULL
is returned.
Will only expand Built in CVS variables all others are ignored.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "cvs.h"
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#if HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
static char *expand_variable PROTO((char *env));
extern char *xmalloc ();
extern void free ();
char *
expand_path (name)
char *name;
{
char *s;
char *d;
char mybuf[PATH_MAX];
char buf[PATH_MAX];
char *result;
s = name;
d = mybuf;
while ((*d++ = *s))
if (*s++ == '$')
{
char *p = d;
char *e;
int flag = (*s == '{');
for (; (*d++ = *s); s++)
if (flag ? *s =='}' :
isalnum (*s) == 0 && *s!='_' )
break;
*--d = 0;
e = expand_variable (&p[flag]);
if (e)
{
for (d = &p[-1]; (*d++ = *e++);)
;
--d;
if (flag && *s)
s++;
}
else
return NULL; /* no env variable */
}
*d = 0;
s = mybuf;
d = buf;
/* If you don't want ~username ~/ to be expanded simply remove
* This entire if statement including the else portion
*/
if (*s++ == '~')
{
char *t;
char *p=s;
if (*s=='/' || *s==0)
t = getenv ("HOME");
else
{
struct passwd *ps;
for (; *p!='/' && *p; p++)
;
*p = 0;
ps = getpwnam (s);
if (ps == 0)
return NULL; /* no such user */
t = ps->pw_dir;
}
while ((*d++ = *t++))
;
--d;
if (*p == 0)
*p = '/'; /* always add / */
s=p;
}
else
--s;
/* Kill up to here */
while ((*d++ = *s++))
;
*d=0;
result = xmalloc (sizeof(char) * strlen(buf)+1);
strcpy (result, buf);
return result;
}
static char *
expand_variable (name)
char *name;
{
/* There is nothing expanding this function to allow it
* to read a file in the $CVSROOT/CVSROOT directory that
* says which environmental variables could be expanded
* or just say everything is fair game to be expanded
*/
if ( strcmp (name, CVSROOT_ENV) == 0 )
return CVSroot;
else
if ( strcmp (name, RCSBIN_ENV) == 0 )
return Rcsbin;
else
if ( strcmp (name, EDITOR1_ENV) == 0 )
return Editor;
else
if ( strcmp (name, EDITOR2_ENV) == 0 )
return Editor;
else
if ( strcmp (name, EDITOR3_ENV) == 0 )
return Editor;
else
return NULL;
/* The code here could also just
* return whatever getenv would
* return.
*/
}

View file

@ -1,275 +0,0 @@
/*
* 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.4 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 const char rcsid[] = "$CVSid: @(#)find_names.c 1.45 94/10/22 $";
USE(rcsid);
#endif
static int find_dirs PROTO((char *dir, List * list, int checkadm));
static int find_rcs PROTO((char *dir, List * list));
static List *filelist;
/*
* add the key from entry on entries list to the files list
*/
static int add_entries_proc PROTO((Node *, void *));
static int
add_entries_proc (node, closure)
Node *node;
void *closure;
{
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 PROTO ((const Node *, const Node *));
static int
fsortcmp (p, q)
const Node *p;
const Node *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 = Entries_Open (aflag);
if (entries != NULL)
{
/* walk the entries file adding elements to the files list */
(void) walklist (entries, add_entries_proc, NULL);
/* if our caller wanted the entries list, return it; else free it */
if (optentries != NULL)
*optentries = entries;
else
Entries_Close (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;
struct dirent *dp;
DIR *dirp;
/* set up to read the dir */
if ((dirp = opendir (dir)) == NULL)
return (1);
/* read the dir, grabbing the ,v files */
while ((dp = readdir (dirp)) != NULL)
{
if (fnmatch (RCSPAT, dp->d_name, 0) == 0)
{
char *comma;
comma = strrchr (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;
char tmp[PATH_MAX];
struct dirent *dp;
DIR *dirp;
/* 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)
continue;
#ifdef DT_DIR
if (dp->d_type != DT_DIR)
{
if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_LNK)
continue;
#endif
/* don't bother stating ,v files */
if (fnmatch (RCSPAT, dp->d_name, 0) == 0)
continue;
sprintf (tmp, "%s/%s", dir, dp->d_name);
if (!isdir (tmp))
continue;
#ifdef DT_DIR
}
#endif
/* check for administration directories (if needed) */
if (checkadm)
{
/* blow off symbolic links to dirs in local dir */
#ifdef DT_DIR
if (dp->d_type != DT_DIR)
{
/* we're either unknown or a symlink at this point */
if (dp->d_type == DT_LNK)
continue;
#endif
if (islink (tmp))
continue;
#ifdef DT_DIR
}
#endif
/* check for new style */
(void) sprintf (tmp, "%s/%s/%s", dir, dp->d_name, CVSADM);
if (!isdir (tmp))
continue;
}
/* put it in the list */
p = getnode ();
p->type = DIRS;
p->key = xstrdup (dp->d_name);
if (addnode (list, p) != 0)
freenode (p);
}
(void) closedir (dirp);
return (0);
}

File diff suppressed because it is too large Load diff

View file

@ -1,286 +0,0 @@
/*
* .cvsignore file support contributed by David G. Grubbs <dgg@odi.com>
*/
#include "cvs.h"
#ifndef lint
static const char rcsid[] = "$CVSid: @(#)ignore.c 1.16 94/09/24 $";
USE(rcsid);
#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 */
const 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 ()
{
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);
#ifdef CLIENT_SUPPORT
/* Chances are we should have some way to provide this feature
client/server, but I'm not sure how (surely not by introducing
another network turnaround to each operation--perhaps by
putting a file in the CVS directory on checkout, or with some
sort of "slave cvsroot" on the client). */
if (!client_active)
#endif
{
/* Then add entries found in repository, if it exists */
(void) sprintf (file, "%s/%s/%s", CVSroot, CVSROOTADM,
CVSROOTADM_IGNORE);
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);
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 */
fp = fopen (file, "r");
if (fp == NULL)
{
if (! existence_error (errno))
error (0, errno, "cannot open %s", file);
return;
}
while (fgets (line, sizeof (line), fp))
ign_add (line, hold);
if (fclose (fp) < 0)
error (0, errno, "cannot close %s", file);
}
/* 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 ((!*(ign+1) || 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);
}
static char **dir_ign_list = NULL;
static int dir_ign_max = 0;
static int dir_ign_current = 0;
/* add a directory to list of dirs to ignore */
void ign_dir_add (name)
char *name;
{
/* make sure we've got the space for the entry */
if (dir_ign_current <= dir_ign_max)
{
dir_ign_max += IGN_GROW;
dir_ign_list = (char **) xrealloc ((char *) dir_ign_list, (dir_ign_max+1) * sizeof(char*));
}
dir_ign_list[dir_ign_current] = name;
dir_ign_current += 1 ;
}
/* this function returns 1 (true) if the given directory name is part of
* the list of directories to ignore
*/
int ignore_directory (name)
char *name;
{
int i;
if (!dir_ign_list)
return 0;
i = dir_ign_current;
while (i--)
{
if (strncmp(name, dir_ign_list[i], strlen(dir_ign_list[i])) == 0)
return 1;
}
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -1,608 +0,0 @@
/*
* 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.4 kit.
*
* Set Lock
*
* Lock file support for CVS.
*/
#include "cvs.h"
#ifndef lint
static const char rcsid[] = "$CVSid: @(#)lock.c 1.50 94/09/30 $";
USE(rcsid);
#endif
static int readers_exist PROTO((char *repository));
static int set_lock PROTO((char *repository, int will_wait));
static void clear_lock PROTO((void));
static void set_lockers_name PROTO((struct stat *statp));
static int set_writelock_proc PROTO((Node * p, void *closure));
static int unlock_proc PROTO((Node * p, void *closure));
static int write_lock PROTO((char *repository));
static void unlock PROTO((char *repository));
static void lock_wait PROTO((char *repository));
static int Check_Owner PROTO((char *lockdir));
static char lockers_name[20];
static char *repository;
static char readlock[PATH_MAX], writelock[PATH_MAX], masterlock[PATH_MAX];
static int cleanup_lckdir;
static List *locklist;
#define L_OK 0 /* success */
#define L_ERROR 1 /* error condition */
#define L_LOCKED 2 /* 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, NULL);
locklist = (List *) NULL;
}
}
/*
* walklist proc for removing a list of locks
*/
static int
unlock_proc (p, closure)
Node *p;
void *closure;
{
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];
if (readlock[0] != '\0')
{
(void) sprintf (tmp, "%s/%s", repository, readlock);
if (unlink (tmp) < 0 && ! existence_error (errno))
error (0, errno, "failed to remove lock %s", tmp);
}
if (writelock[0] != '\0')
{
(void) sprintf (tmp, "%s/%s", repository, writelock);
if (unlink (tmp) < 0 && ! existence_error (errno))
error (0, errno, "failed to remove lock %s", 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.
*/
if (writelock[0] != '\0' || (readlock[0] != '\0' && cleanup_lckdir))
{
(void) sprintf (tmp, "%s/%s", repository, CVSLCK);
if (Check_Owner(tmp))
{
#ifdef AFSCVS
char rmuidlock[PATH_MAX];
sprintf(rmuidlock, "rm -f %s/uidlock%d", tmp, geteuid() );
system(rmuidlock);
#endif
(void) rmdir (tmp);
}
}
cleanup_lckdir = 0;
}
/*
* Check the owner of a lock. Returns 1 if we own it, 0 otherwise.
*/
static int
Check_Owner(lockdir)
char *lockdir;
{
struct stat sb;
#ifdef AFSCVS
/* In the Andrew File System (AFS), user ids from stat don't match
those from geteuid(). The AFSCVS code can deal with either AFS or
non-AFS repositories; the non-AFSCVS code is faster. */
char uidlock[PATH_MAX];
/* Check if the uidlock is in the lock directory */
sprintf(uidlock, "%s/uidlock%d", lockdir, geteuid() );
if( stat(uidlock, &sb) != -1)
return 1; /* The file exists, therefore we own the lock */
else
return 0; /* The file didn't exist or some other error.
* Assume that we don't own it.
*/
#else
if (stat (lockdir, &sb) != -1 && sb.st_uid == geteuid ())
return 1;
else
return 0;
#endif
} /* end Check_Owner() */
/*
* 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,
#ifdef HAVE_LONG_FILE_NAMES
"%s.%s.%d", CVSRFL, hostname,
#else
"%s.%d", CVSRFL,
#endif
getpid ());
/* remember what we're locking (for lock_cleanup) */
repository = xrepository;
#ifdef BOGUS_UNLESS_PROVEN_OTHERWISE
/* make sure we can write the repository */
(void) sprintf (tmp,
#ifdef HAVE_LONG_FILE_NAMES
"%s/%s.%s.%d", xrepository, CVSTFL, hostname,
#else
"%s/%s.%d", xrepository, CVSTFL,
#endif
getpid());
if ((fp = fopen (tmp, "w+")) == NULL || fclose (fp) == EOF)
{
error (0, errno, "cannot create read lock in repository `%s'",
xrepository);
readlock[0] = '\0';
if (unlink (tmp) < 0 && ! existence_error (errno))
error (0, errno, "failed to remove lock %s", tmp);
return (1);
}
if (unlink (tmp) < 0)
error (0, errno, "failed to remove lock %s", tmp);
#endif
/* get the lock dir for our own */
if (set_lock (xrepository, 1) != 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 */
clear_lock();
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, NULL);
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, closure)
Node *p;
void *closure;
{
/* 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,
#ifdef HAVE_LONG_FILE_NAMES
"%s.%s.%d", CVSWFL, hostname,
#else
"%s.%d", CVSWFL,
#endif
getpid());
#ifdef BOGUS_UNLESS_PROVEN_OTHERWISE
/* make sure we can write the repository */
(void) sprintf (tmp,
#ifdef HAVE_LONG_FILE_NAMES
"%s/%s.%s.%d", repository, CVSTFL, hostname,
#else
"%s/%s.%d", repository, CVSTFL,
#endif
getpid ());
if ((fp = fopen (tmp, "w+")) == NULL || fclose (fp) == EOF)
{
error (0, errno, "cannot create write lock in repository `%s'",
repository);
if (unlink (tmp) < 0 && ! existence_error (errno))
error (0, errno, "failed to remove lock %s", tmp);
return (L_ERROR);
}
if (unlink (tmp) < 0)
error (0, errno, "failed to remove lock %s", tmp);
#endif
/* make sure the lock dir is ours (not necessarily unique to us!) */
status = set_lock (repository, 0);
if (status == L_OK)
{
/* 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)
{
clear_lock();
}
/* 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;
if (unlink (tmp) < 0 && ! existence_error (errno))
error (0, errno, "failed to remove lock %s", tmp);
/* free the lock dir if we created it */
if (status == L_OK)
{
clear_lock();
}
/* 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 dirent *dp;
struct stat sb;
int ret = 0;
#ifdef CVS_FUDGELOCKS
again:
#endif
if ((dirp = opendir (repository)) == NULL)
error (1, 0, "cannot open directory %s", repository);
errno = 0;
while ((dp = readdir (dirp)) != NULL)
{
if (fnmatch (CVSRFLPAT, dp->d_name, 0) == 0)
{
#ifdef CVS_FUDGELOCKS
time_t now;
(void) time (&now);
#endif
(void) sprintf (line, "%s/%s", repository, dp->d_name);
if (stat (line, &sb) != -1)
{
#ifdef CVS_FUDGELOCKS
/*
* 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 (now >= (sb.st_ctime + CVSLCKAGE) && unlink (line) != -1)
{
(void) closedir (dirp);
goto again;
}
#endif
set_lockers_name (&sb);
}
ret = 1;
break;
}
errno = 0;
}
if (errno != 0)
error (0, errno, "error reading directory %s", repository);
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%lu", (unsigned long) 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 (repository, will_wait)
char *repository;
int will_wait;
{
struct stat sb;
mode_t omask;
#ifdef CVS_FUDGELOCKS
time_t now;
#endif
(void) sprintf (masterlock, "%s/%s", repository, CVSLCK);
/*
* 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 (;;)
{
int status = -1;
omask = umask (cvsumask);
SIG_beginCrSect ();
if (CVS_MKDIR (masterlock, 0777) == 0)
{
#ifdef AFSCVS
char uidlock[PATH_MAX];
FILE *fp;
sprintf(uidlock, "%s/uidlock%d", masterlock, geteuid() );
if ((fp = fopen(uidlock, "w+")) == NULL)
{
/* We failed to create the uidlock,
so rm masterlock and leave */
rmdir(masterlock);
SIG_endCrSect ();
status = L_ERROR;
goto out;
}
/* We successfully created the uid lock, so close the file */
fclose(fp);
#endif
cleanup_lckdir = 1;
SIG_endCrSect ();
status = L_OK;
goto out;
}
SIG_endCrSect ();
out:
(void) umask (omask);
if (status != -1)
return status;
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 (masterlock, &sb) < 0)
{
if (existence_error (errno))
continue;
error (0, errno, "couldn't stat lock directory `%s'", masterlock);
return (L_ERROR);
}
#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))
{
#ifdef AFSCVS
/* Remove the uidlock first */
char rmuidlock[PATH_MAX];
sprintf(rmuidlock, "rm -f %s/uidlock%d", masterlock, geteuid() );
system(rmuidlock);
#endif
if (rmdir (masterlock) >= 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);
}
}
/*
* Clear master lock. We don't have to recompute the lock name since
* clear_lock is never called except after a successful set_lock().
*/
static void
clear_lock()
{
#ifdef AFSCVS
/* Remove the uidlock first */
char rmuidlock[PATH_MAX];
sprintf(rmuidlock, "rm -f %s/uidlock%d", masterlock, geteuid() );
system(rmuidlock);
#endif
if (rmdir (masterlock) < 0)
error (0, errno, "failed to remove lock dir `%s'", masterlock);
cleanup_lckdir = 0;
}
/*
* 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);
}

View file

@ -1,178 +0,0 @@
/*
* 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.4 kit.
*
* Print Log Information
*
* This line exists solely to test some pcl-cvs/ChangeLog stuff. You
* can delete it, if indeed it's still here when you read it. -Karl
*
* 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 const char rcsid[] = "$CVSid: @(#)log.c 1.44 94/09/30 $";
USE(rcsid);
#endif
static Dtype log_dirproc PROTO((char *dir, char *repository, char *update_dir));
static int log_fileproc PROTO((char *file, char *update_dir, char *repository,
List * entries, List * srcfiles));
static const char *const log_usage[] =
{
"Usage: %s %s [-l] [rlog-options] [files...]\n",
"\t-l\tLocal directory only, no recursion.\n",
NULL
};
static int ac;
static char **av;
int
cvslog (argc, argv)
int argc;
char **argv;
{
int i;
int err = 0;
int local = 0;
if (argc == -1)
usage (log_usage);
/*
* All 'log' command options except -l are passed directly on to 'rlog'
*/
for (i = 1; i < argc && argv[i][0] == '-'; i++)
if (argv[i][1] == 'l')
local = 1;
wrap_setup ();
#ifdef CLIENT_SUPPORT
if (client_active) {
/* We're the local client. Fire up the remote server. */
start_server ();
ign_setup ();
for (i = 1; i < argc && argv[i][0] == '-'; i++)
send_arg (argv[i]);
#if 0
/* FIXME: We shouldn't have to send current files to get log entries, but it
doesn't work yet and I haven't debugged it. So send the files --
it's slower but it works. gnu@cygnus.com Apr94 */
send_file_names (argc - i, argv + i);
#else
send_files (argc - i, argv + i, local, 0);
#endif
if (fprintf (to_server, "log\n") < 0)
error (1, errno, "writing to server");
err = get_responses_and_close ();
return err;
}
ac = argc;
av = argv;
#endif
err = start_recursion (log_fileproc, (FILESDONEPROC) NULL, log_dirproc,
(DIRLEAVEPROC) NULL, argc - i, argv + i, local,
W_LOCAL | W_REPOS | W_ATTIC, 0, 1,
(char *) NULL, 1, 0);
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)
{
/* no rcs file. What *do* we know about this file? */
p = findnode (entries, file);
if (p != NULL)
{
Entnode *e;
e = (Entnode *) p->data;
if (e->version[0] == '0' || e->version[1] == '\0')
{
if (!really_quiet)
error (0, 0, "%s has been added, but not committed",
file);
return(0);
}
}
if (!really_quiet)
error (0, 0, "nothing known about %s", file);
return (1);
}
run_setup ("%s%s", Rcsbin, RCS_RLOG);
{
int i;
for (i = 1; i < ac && av[i][0] == '-'; i++)
if (av[i][1] != 'l')
run_arg (av[i]);
}
run_arg (rcsfile->path);
if (*update_dir)
{
char *workfile = xmalloc (strlen (update_dir) + strlen (file) + 2);
sprintf (workfile, "%s/%s", update_dir, file);
run_arg (workfile);
free (workfile);
}
if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_REALLY)) == -1)
{
error (1, errno, "fork failed for rlog on %s", file);
}
return (retcode);
}
/*
* Print a warm fuzzy message
*/
/* ARGSUSED */
static Dtype
log_dirproc (dir, repository, update_dir)
char *dir;
char *repository;
char *update_dir;
{
if (!isdir (dir))
return (R_SKIP_ALL);
if (!quiet)
error (0, 0, "Logging %s", update_dir);
return (R_PROCESS);
}

View file

@ -1,287 +0,0 @@
/*
* Copyright (c) 1995, Cyclic Software, Bloomington, IN, USA
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with CVS.
*
* Allow user to log in for an authenticating server.
*/
#include "cvs.h"
#ifdef AUTH_CLIENT_SUPPORT /* This covers the rest of the file. */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#ifndef lint
static const char rcsid[] = "$CVSid: @(#)login.c 1.1 95/10/01 $";
USE(rcsid);
#endif
#ifndef CVS_PASSWORD_FILE
#define CVS_PASSWORD_FILE ".cvspass"
#endif
/* The return value will need to be freed. */
char *
construct_cvspass_filename ()
{
char *homedir;
char *passfile;
/* Construct absolute pathname to user's password file. */
/* todo: does this work under Win-NT and OS/2 ? */
homedir = getenv ("HOME");
if (! homedir)
{
error (1, errno, "could not find out home directory");
return (char *) NULL;
}
passfile =
(char *) xmalloc (strlen (homedir) + strlen (CVS_PASSWORD_FILE) + 3);
strcpy (passfile, homedir);
strcat (passfile, "/");
strcat (passfile, CVS_PASSWORD_FILE);
/* Safety first and last, Scouts. */
if (isfile (passfile))
/* xchmod() is too polite. */
chmod (passfile, 0600);
return passfile;
}
/* Prompt for a password, and store it in the file "CVS/.cvspass".
*
* Because the user might be accessing multiple repositories, with
* different passwords for each one, the format of ~/.cvspass is:
*
* user@host:/path cleartext_password
* user@host:/path cleartext_password
* ...
*
* Of course, the "user@" might be left off -- it's just based on the
* value of CVSroot.
*
* Like .netrc, the file's permissions are the only thing preventing
* it from being read by others. Unlike .netrc, we will not be
* fascist about it, at most issuing a warning, and never refusing to
* work.
*/
int
login (argc, argv)
int argc;
char **argv;
{
char *username;
int i;
char *passfile;
FILE *fp;
char *typed_password, *found_password;
char linebuf[MAXLINELEN];
int root_len, already_entered = 0;
/* Make this a "fully-qualified" CVSroot if necessary. */
if (! strchr (CVSroot, '@'))
{
/* We need to prepend "user@host:". */
char *tmp;
printf ("Repository \"%s\" not fully-qualified.\n", CVSroot);
printf ("Please enter \"user@host:/path\": ");
fflush (stdout);
fgets (linebuf, MAXLINELEN, stdin);
tmp = xmalloc (strlen (linebuf) + 1);
strcpy (tmp, linebuf);
tmp[strlen (linebuf) - 1] = '\0';
CVSroot = tmp;
}
/* Check to make sure it's fully-qualified before going on. */
if (! CVSroot)
{
error (1, 0, "CVSroot is NULL");
}
else if ((! strchr (CVSroot, '@')) && (! strchr (CVSroot, ':')))
{
error (1, 0, "CVSroot not fully-qualified: %s", CVSroot);
}
passfile = construct_cvspass_filename ();
typed_password = getpass ("Enter CVS password: ");
/* IF we have a password for this "[user@]host:/path" already
* THEN
* IF it's the same as the password we read from the prompt
* THEN
* do nothing
* ELSE
* replace the old password with the new one
* ELSE
* append new entry to the end of the file.
*/
root_len = strlen (CVSroot);
/* Yes, the method below reads the user's password file twice. It's
inefficient, but we're not talking about a gig of data here. */
fp = fopen (passfile, "r");
if (fp == NULL)
{
error (1, errno, "unable to open %s", passfile);
return 1;
}
/* Check each line to see if we have this entry already. */
while (fgets (linebuf, MAXLINELEN, fp) != NULL)
{
if (! strncmp (CVSroot, linebuf, root_len))
{
already_entered = 1;
break;
}
}
fclose (fp);
if (already_entered)
{
/* This user/host has a password in the file already. */
/* todo: what about these charsets??? */
strtok (linebuf, " \n");
found_password = strtok (NULL, " \n");
if (strcmp (found_password, typed_password))
{
/* typed_password and found_password don't match, so we'll
* have to update passfile. We replace the old password
* with the new one by writing a tmp file whose contents are
* exactly the same as passfile except that this one entry
* gets typed_password instead of found_password. Then we
* rename the tmp file on top of passfile.
*/
char *tmp_name;
FILE *tmp_fp;
tmp_name = tmpnam (NULL);
if ((tmp_fp = fopen (tmp_name, "w")) == NULL)
{
error (1, errno, "unable to open temp file %s", tmp_name);
return 1;
}
chmod (tmp_name, 0600);
fp = fopen (passfile, "r");
if (fp == NULL)
{
error (1, errno, "unable to open %s", passfile);
return 1;
}
/* I'm not paranoid, they really ARE out to get me: */
chmod (passfile, 0600);
while (fgets (linebuf, MAXLINELEN, fp) != NULL)
{
if (strncmp (CVSroot, linebuf, root_len))
fprintf (tmp_fp, "%s", linebuf);
else
fprintf (tmp_fp, "%s %s\n", CVSroot, typed_password);
}
fclose (tmp_fp);
fclose (fp);
rename_file (tmp_name, passfile);
chmod (passfile, 0600);
}
}
else
{
if ((fp = fopen (passfile, "a")) == NULL)
{
error (1, errno, "could not open %s", passfile);
free (passfile);
return 1;
}
/* It's safer this way, and blank lines in the file are OK. */
fprintf (fp, "\n%s %s\n", CVSroot, typed_password);
fclose (fp);
}
/* Utter, total, raving paranoia, I know. */
chmod (passfile, 0600);
memset (typed_password, 0, strlen (typed_password));
free (passfile);
return 0;
}
/* todo: "cvs logout" could erase an entry from the file.
* But to what purpose?
*/
char *
get_cvs_password (user, host, cvsroot)
{
int root_len;
int found_it = 0;
char *password;
char linebuf[MAXLINELEN];
FILE *fp;
char *passfile;
passfile = construct_cvspass_filename ();
fp = fopen (passfile, "r");
if (fp == NULL)
{
error (0, errno, "could not open %s", passfile);
free (passfile);
goto prompt_for_it;
}
root_len = strlen (CVSroot);
/* Check each line to see if we have this entry already. */
while (fgets (linebuf, MAXLINELEN, fp) != NULL)
{
if (strncmp (CVSroot, linebuf, root_len) == 0)
{
/* This is it! So break out and deal with linebuf. */
found_it = 1;
break;
}
}
if (found_it)
{
/* linebuf now contains the line with the password. */
char *tmp;
strtok (linebuf, " ");
password = strtok (NULL, "\n");
/* Give it permanent storage. */
tmp = xmalloc (strlen (password) + 1);
strcpy (tmp, password);
tmp[strlen (password)] = '\0';
memset (password, 0, strlen (password));
return tmp;
}
else
{
prompt_for_it:
return getpass ("CVS password: ");
}
}
#endif /* AUTH_CLIENT_SUPPORT from beginning of file. */

View file

@ -1,486 +0,0 @@
/*
* 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.4 kit.
*/
#include "cvs.h"
#include "getline.h"
#ifndef lint
static const char rcsid[] = "$CVSid: @(#)logmsg.c 1.48 94/09/29 $";
USE(rcsid);
#endif
static int find_type PROTO((Node * p, void *closure));
static int fmt_proc PROTO((Node * p, void *closure));
static int logfile_write PROTO((char *repository, char *filter, char *title,
char *message, char *revision, FILE * logfp,
List * changes));
static int rcsinfo_proc PROTO((char *repository, char *template));
static int title_proc PROTO((Node * p, void *closure));
static int update_logfile_proc PROTO((char *repository, char *filter));
static void setup_tmpfile PROTO((FILE * xfp, char *xprefix, List * changes));
static int editinfo_proc PROTO((char *repository, char *template));
static FILE *fp;
static char *str_list;
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, NULL) != 0)
{
(void) fprintf (fp, "%sModified Files:\n", prefix);
(void) fprintf (fp, "%s\t", prefix);
col = 8;
(void) walklist (changes, fmt_proc, NULL);
(void) fprintf (fp, "\n");
}
type = T_ADDED;
if (walklist (changes, find_type, NULL) != 0)
{
(void) fprintf (fp, "%sAdded Files:\n", prefix);
(void) fprintf (fp, "%s\t", prefix);
col = 8;
(void) walklist (changes, fmt_proc, NULL);
(void) fprintf (fp, "\n");
}
type = T_REMOVED;
if (walklist (changes, find_type, NULL) != 0)
{
(void) fprintf (fp, "%sRemoved Files:\n", prefix);
(void) fprintf (fp, "%s\t", prefix);
col = 8;
(void) walklist (changes, fmt_proc, NULL);
(void) fprintf (fp, "\n");
}
}
/*
* Looks for nodes of a specified type and returns 1 if found
*/
static int
find_type (p, closure)
Node *p;
void *closure;
{
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, closure)
Node *p;
void *closure;
{
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, messagep, repository, changes)
char *dir;
char **messagep;
char *repository;
List *changes;
{
static int reuse_log_message = 0;
char *line;
int line_length;
size_t line_chars_allocated;
char fname[L_tmpnam+1];
struct stat pre_stbuf, post_stbuf;
int retcode = 0;
char *p;
if (noexec || reuse_log_message)
return;
/* Create a temporary file */
(void) tmpnam (fname);
again:
if ((fp = fopen (fname, "w+")) == NULL)
error (1, 0, "cannot create temporary file %s", fname);
if (*messagep)
{
(void) fprintf (fp, "%s", *messagep);
if ((*messagep)[strlen (*messagep) - 1] != '\n')
(void) fprintf (fp, "\n");
}
else
(void) fprintf (fp, "\n");
if (repository != NULL)
/* 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 && *dir)
(void) fprintf (fp, "%sCommitting in %s\n%s\n", CVSEDITPREFIX,
dir, CVSEDITPREFIX);
if (changes != NULL)
setup_tmpfile (fp, CVSEDITPREFIX, changes);
(void) fprintf (fp,
"%s----------------------------------------------------------------------\n",
CVSEDITPREFIX);
/* finish off the temp file */
if (fclose (fp) == EOF)
error (1, errno, "%s", fname);
if (stat (fname, &pre_stbuf) == -1)
pre_stbuf.st_mtime = 0;
if (editinfo_editor)
free (editinfo_editor);
editinfo_editor = (char *) NULL;
if (repository != 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 *messagep variable */
fp = open_file (fname, "r");
if (*messagep)
free (*messagep);
if (stat (fname, &post_stbuf) != 0)
error (1, errno, "cannot find size of temp file %s", fname);
if (post_stbuf.st_size == 0)
*messagep = NULL;
else
{
*messagep = (char *) xmalloc (post_stbuf.st_size + 1);
*messagep[0] = '\0';
}
line = NULL;
line_chars_allocated = 0;
if (*messagep)
{
p = *messagep;
while (1)
{
line_length = getline (&line, &line_chars_allocated, fp);
if (line_length == -1)
{
if (ferror (fp))
error (0, errno, "warning: cannot read %s", fname);
break;
}
if (strncmp (line, CVSEDITPREFIX, sizeof (CVSEDITPREFIX) - 1) == 0)
continue;
(void) strcpy (p, line);
p += line_length;
}
}
if (fclose (fp) < 0)
error (0, errno, "warning: cannot close %s", fname);
if (pre_stbuf.st_mtime == post_stbuf.st_mtime ||
*messagep == NULL ||
strcmp (*messagep, "\n") == 0)
{
for (;;)
{
(void) printf ("\nLog message unchanged or not specified\n");
(void) printf ("a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs\n");
(void) printf ("Action: (continue) ");
(void) fflush (stdout);
line_length = getline (&line, &line_chars_allocated, stdin);
if (line_length <= 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");
}
}
if (line)
free (line);
if (unlink_file (fname) < 0)
error (0, errno, "warning: cannot remove temp file %s", 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;
/* 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)
{
char *line = NULL;
size_t line_chars_allocated = 0;
while (getline (&line, &line_chars_allocated, tfp) >= 0)
(void) fputs (line, fp);
if (ferror (tfp))
error (0, errno, "warning: cannot read %s", template);
if (fclose (tfp) < 0)
error (0, errno, "warning: cannot close %s", template);
if (line)
free (line);
return (0);
}
else
{
error (0, errno, "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;
/* nothing to do if the list is empty */
if (xchanges == NULL || xchanges->list->next == xchanges->list)
return;
/* 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 (!str_list)
str_list = xmalloc (MAXLISTLEN);
str_list[0] = '\0';
type = T_TITLE;
(void) walklist (changes, title_proc, NULL);
type = T_ADDED;
(void) walklist (changes, title_proc, NULL);
type = T_MODIFIED;
(void) walklist (changes, title_proc, NULL);
type = T_REMOVED;
(void) walklist (changes, title_proc, NULL);
title = xmalloc (strlen (srepos) + strlen (str_list) + 1 + 2); /* for 's */
(void) sprintf (title, "'%s%s'", srepos, str_list);
/* to be nice, free up this chunk of memory */
free (str_list);
str_list = (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 str_list
*/
static int
title_proc (p, closure)
Node *p;
void *closure;
{
if (p->data == (char *) type)
{
(void) strcat (str_list, " ");
(void) strcat (str_list, 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];
FILE *pipefp, *Popen ();
char *prog = xmalloc (MAXPROGLEN);
char *cp;
int c;
/* XXX <woods@web.net> -- this is gross, ugly, and a hack! FIXME! */
/*
* 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);
}
(void) fprintf (pipefp, "Update of %s\n", repository);
(void) fprintf (pipefp, "In directory %s:%s\n\n", hostname,
((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");
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);
}

View file

@ -1,769 +0,0 @@
/*
* 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.4 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
* login Record user, host, repos, password
* 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"
#if HAVE_KERBEROS
#include <sys/socket.h>
#include <netinet/in.h>
#include <krb.h>
#ifndef HAVE_KRB_GET_ERR_TEXT
#define krb_get_err_text(status) krb_err_txt[status]
#endif
#endif
#ifndef lint
static const char rcsid[] = "$CVSid: @(#)main.c 1.78 94/10/07 $\n";
USE(rcsid);
#endif
char *program_name;
char *program_path;
/*
* Initialize comamnd_name to "cvs" so that the first call to
* read_cvsrc tries to find global cvs options.
*/
char *command_name = "cvs";
/*
* Since some systems don't define this...
*/
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 256
#endif
char hostname[MAXHOSTNAMELEN];
#ifdef AUTH_CLIENT_SUPPORT
int use_authenticating_server = FALSE;
#endif /* AUTH_CLIENT_SUPPORT */
int use_editor = TRUE;
int use_cvsrc = TRUE;
int cvswrite = !CVSREAD_DFLT;
int really_quiet = FALSE;
int quiet = FALSE;
int trace = FALSE;
int noexec = FALSE;
int logoff = FALSE;
mode_t cvsumask = UMASK_DFLT;
char *CurDir;
/*
* Defaults, for the environment variables that are not set
*/
char *Rcsbin = RCSBIN_DFLT;
char *Editor = EDITOR_DFLT;
char *CVSroot = CVSROOT_DFLT;
#ifdef CVSADM_ROOT
/*
* The path found in CVS/Root must match $CVSROOT and/or 'cvs -d root'
*/
char *CVSADM_Root = CVSROOT_DFLT;
#endif /* CVSADM_ROOT */
int add PROTO((int argc, char **argv));
int admin PROTO((int argc, char **argv));
int checkout PROTO((int argc, char **argv));
int commit PROTO((int argc, char **argv));
int diff PROTO((int argc, char **argv));
int history PROTO((int argc, char **argv));
int import PROTO((int argc, char **argv));
int cvslog PROTO((int argc, char **argv));
#ifdef AUTH_CLIENT_SUPPORT
int login PROTO((int argc, char **argv));
#endif /* AUTH_CLIENT_SUPPORT */
int patch PROTO((int argc, char **argv));
int release PROTO((int argc, char **argv));
int cvsremove PROTO((int argc, char **argv));
int rtag PROTO((int argc, char **argv));
int status PROTO((int argc, char **argv));
int tag PROTO((int argc, char **argv));
int update PROTO((int argc, char **argv));
const 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. */
#ifdef CLIENT_SUPPORT
int (*client_func) (); /* Function to do it via the protocol. */
#endif
} cmds[] =
{
#ifdef CLIENT_SUPPORT
#define CMD_ENTRY(n1, n2, n3, f1, f2) { n1, n2, n3, f1, f2 }
#else
#define CMD_ENTRY(n1, n2, n3, f1, f2) { n1, n2, n3, f1 }
#endif
CMD_ENTRY("add", "ad", "new", add, client_add),
#ifndef CVS_NOADMIN
CMD_ENTRY("admin", "adm", "rcs", admin, client_admin),
#endif
CMD_ENTRY("checkout", "co", "get", checkout, client_checkout),
CMD_ENTRY("commit", "ci", "com", commit, client_commit),
CMD_ENTRY("diff", "di", "dif", diff, client_diff),
CMD_ENTRY("export", "exp", "ex", checkout, client_export),
CMD_ENTRY("history", "hi", "his", history, client_history),
CMD_ENTRY("import", "im", "imp", import, client_import),
CMD_ENTRY("log", "lo", "rlog", cvslog, client_log),
#ifdef AUTH_CLIENT_SUPPORT
CMD_ENTRY("login", "logon", "lgn", login, login),
#endif /* AUTH_CLIENT_SUPPORT */
CMD_ENTRY("rdiff", "patch", "pa", patch, client_rdiff),
CMD_ENTRY("release", "re", "rel", release, client_release),
CMD_ENTRY("remove", "rm", "delete", cvsremove, client_remove),
CMD_ENTRY("status", "st", "stat", status, client_status),
CMD_ENTRY("rtag", "rt", "rfreeze", rtag, client_rtag),
CMD_ENTRY("tag", "ta", "freeze", tag, client_tag),
CMD_ENTRY("update", "up", "upd", update, client_update),
#ifdef SERVER_SUPPORT
/*
* The client_func is also server because we might have picked up a
* CVSROOT environment variable containing a colon. The client will send
* the real root later.
*/
CMD_ENTRY("server", "server", "server", server, server),
#endif
CMD_ENTRY(NULL, NULL, NULL, NULL, NULL),
#undef CMD_ENTRY
};
static const char *const 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",
#ifdef AUTH_CLIENT_SUPPORT
" -a Use the authenticating server, not rsh.\n",
#endif /* AUTH_CLIENT_SUPPORT */
" -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",
" -f Do not use the ~/.cvsrc file\n",
#ifdef CLIENT_SUPPORT
" -z # Use 'gzip -#' for net traffic if possible.\n",
#endif
"\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",
#ifdef AUTH_CLIENT_SUPPORT
" login Prompt for password for authenticating server.\n",
#endif /* AUTH_CLIENT_SUPPORT */
" 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 RETSIGTYPE
main_cleanup ()
{
exit (1);
}
static void
error_cleanup ()
{
Lock_Cleanup();
#ifdef SERVER_SUPPORT
if (server_active)
server_cleanup (0);
#endif
}
int
main (argc, argv)
int argc;
char **argv;
{
extern char *version_string;
extern char *config_string;
char *cp, *end;
const struct cmd *cm;
int c, err = 0;
static int help = FALSE, version_flag = FALSE;
int rcsbin_update_env, cvs_update_env = 0;
char tmp[PATH_MAX];
static struct option long_options[] =
{
{"help", 0, &help, TRUE},
{"version", 0, &version_flag, TRUE},
{0, 0, 0, 0}
};
/* `getopt_long' stores the option index here, but right now we
don't use it. */
int option_index = 0;
error_set_cleanup (error_cleanup);
/* The IBM TCP/IP library under OS/2 needs to be initialized: */
#ifdef NEED_CALL_SOCKINIT
if (SockInit () != TRUE)
{
fprintf (stderr, "SockInit() failed!\n");
exit (1);
}
#endif /* NEED_CALL_SOCKINIT */
/*
* Just save the last component of the path for error messages
*/
program_path = xstrdup (argv[0]);
program_name = last_component (argv[0]);
CurDir = xmalloc (PATH_MAX);
#ifndef SERVER_SUPPORT
if (!getwd (CurDir))
error (1, 0, "cannot get working directory: %s", CurDir);
#endif
/*
* 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 */
cvs_update_env = 0;
if ((cp = getenv (RCSBIN_ENV)) != NULL)
{
Rcsbin = cp;
rcsbin_update_env = 0; /* it's already there */
}
if ((cp = getenv (EDITOR1_ENV)) != NULL)
Editor = cp;
else if ((cp = getenv (EDITOR2_ENV)) != NULL)
Editor = cp;
else if ((cp = getenv (EDITOR3_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;
if ((cp = getenv (CVSUMASK_ENV)) != NULL)
{
/* FIXME: Should be accepting symbolic as well as numeric mask. */
cvsumask = strtol (cp, &end, 8) & 0777;
if (*end != '\0')
error (1, errno, "invalid umask value in %s (%s)",
CVSUMASK_ENV, cp);
}
/*
* Scan cvsrc file for global options.
*/
read_cvsrc(&argc, &argv);
/* This has the effect of setting getopt's ordering to REQUIRE_ORDER,
which is what we need to distinguish between global options and
command options. FIXME: It would appear to be possible to do this
much less kludgily by passing "+" as the first character to the
option string we pass to getopt_long. */
optind = 1;
while ((c = getopt_long
(argc, argv, "Qqrawtnlvb:e:d:Hfz:", long_options, &option_index))
!= EOF)
{
switch (c)
{
case 0:
/* getopt_long took care of setting the flag. */
break;
case 'Q':
really_quiet = TRUE;
/* FALL THROUGH */
case 'q':
quiet = TRUE;
break;
case 'r':
cvswrite = FALSE;
break;
#ifdef AUTH_CLIENT_SUPPORT
case 'a':
use_authenticating_server = TRUE;
break;
#endif /* AUTH_CLIENT_SUPPORT */
case 'w':
cvswrite = TRUE;
break;
case 't':
trace = TRUE;
break;
case 'n':
noexec = TRUE;
case 'l': /* Fall through */
logoff = TRUE;
break;
case 'v':
version_flag = TRUE;
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':
use_cvsrc = FALSE; /* this ensure that cvs -H works */
help = TRUE;
break;
case 'f':
use_cvsrc = FALSE;
break;
#ifdef CLIENT_SUPPORT
case 'z':
gzip_level = atoi (optarg);
if (gzip_level <= 0 || gzip_level > 9)
error (1, 0,
"gzip compression level must be between 1 and 9");
break;
#endif
case '?':
default:
usage (usg);
}
}
if (version_flag == TRUE)
{
(void) fputs (version_string, stdout);
(void) fputs (config_string, stdout);
(void) sprintf (tmp, "Patch Level: %d\n", PATCHLEVEL);
(void) fputs (tmp, stdout);
(void) fputs ("\n", stdout);
(void) fputs ("Copyright (c) 1993-1994 Brian Berliner\n", stdout);
(void) fputs ("Copyright (c) 1993-1994 david d `zoo' zuhn\n", stdout);
(void) fputs ("Copyright (c) 1992, Brian Berliner and Jeff Polk\n", stdout);
(void) fputs ("Copyright (c) 1989-1992, Brian Berliner\n", stdout);
(void) fputs ("\n", stdout);
(void) fputs ("CVS may be copied only under the terms of the GNU General Public License,\n", stdout);
(void) fputs ("a copy of which can be found with the CVS distribution kit.\n", stdout);
exit (0);
}
argc -= optind;
argv += optind;
if (argc < 1)
usage (usg);
#ifdef HAVE_KERBEROS
/* If we are invoked with a single argument "kserver", then we are
running as Kerberos server as root. Do the authentication as
the very first thing, to minimize the amount of time we are
running as root. */
if (strcmp (argv[0], "kserver") == 0)
{
int status;
char instance[INST_SZ];
struct sockaddr_in peer;
struct sockaddr_in laddr;
int len;
KTEXT_ST ticket;
AUTH_DAT auth;
char version[KRB_SENDAUTH_VLEN];
Key_schedule sched;
char user[ANAME_SZ];
struct passwd *pw;
strcpy (instance, "*");
len = sizeof peer;
if (getpeername (STDIN_FILENO, (struct sockaddr *) &peer, &len) < 0
|| getsockname (STDIN_FILENO, (struct sockaddr *) &laddr,
&len) < 0)
{
printf ("E Fatal error, aborting.\n\
error %s getpeername or getsockname failed\n", strerror (errno));
exit (1);
}
status = krb_recvauth (KOPT_DO_MUTUAL, STDIN_FILENO, &ticket, "rcmd",
instance, &peer, &laddr, &auth, "", sched,
version);
if (status != KSUCCESS)
{
printf ("E Fatal error, aborting.\n\
error 0 kerberos: %s\n", krb_get_err_text(status));
exit (1);
}
/* Get the local name. */
status = krb_kntoln (&auth, user);
if (status != KSUCCESS)
{
printf ("E Fatal error, aborting.\n\
error 0 kerberos: can't get local name: %s\n", krb_get_err_text(status));
exit (1);
}
pw = getpwnam (user);
if (pw == NULL)
{
printf ("E Fatal error, aborting.\n\
error 0 %s: no such user\n", user);
exit (1);
}
initgroups (pw->pw_name, pw->pw_gid);
setgid (pw->pw_gid);
setuid (pw->pw_uid);
/* Inhibit access by randoms. Don't want people randomly
changing our temporary tree before we check things in. */
umask (077);
#if HAVE_PUTENV
/* Set LOGNAME and USER in the environment, in case they are
already set to something else. */
{
char *env;
env = xmalloc (sizeof "LOGNAME=" + strlen (user));
(void) sprintf (env, "LOGNAME=%s", user);
(void) putenv (env);
env = xmalloc (sizeof "USER=" + strlen (user));
(void) sprintf (env, "USER=%s", user);
(void) putenv (env);
}
#endif
/* Pretend we were invoked as a plain server. */
argv[0] = "server";
}
#endif /* HAVE_KERBEROS */
#if defined(AUTH_SERVER_SUPPORT) && defined(SERVER_SUPPORT)
if (strcmp (argv[0], "pserver") == 0)
{
/* Gets username and password from client, authenticates, then
switches to run as that user and sends an ACK back to the
client. */
authenticate_connection ();
/* Pretend we were invoked as a plain server. */
argv[0] = "server";
}
#endif /* AUTH_SERVER_SUPPORT && SERVER_SUPPORT */
#ifdef CVSADM_ROOT
/*
* See if we are able to find a 'better' value for CVSroot in the
* CVSADM_ROOT directory.
*/
#ifdef SERVER_SUPPORT
if (strcmp (argv[0], "server") == 0 && CVSroot == NULL)
CVSADM_Root = NULL;
else
CVSADM_Root = Name_Root((char *) NULL, (char *) NULL);
#else /* No SERVER_SUPPORT */
CVSADM_Root = Name_Root((char *) NULL, (char *) NULL);
#endif /* No SERVER_SUPPORT */
if (CVSADM_Root != NULL)
{
if (CVSroot == NULL || !cvs_update_env)
{
CVSroot = CVSADM_Root;
cvs_update_env = 1; /* need to update environment */
}
#ifdef CLIENT_SUPPORT
else if (!getenv ("CVS_IGNORE_REMOTE_ROOT"))
#else
else
#endif
{
/*
* Now for the hard part, compare the two directories. If they
* are not identical, then abort this command.
*/
if ((fncmp (CVSroot, CVSADM_Root) != 0) &&
!same_directories(CVSroot, CVSADM_Root))
{
error (0, 0, "%s value for CVS Root found in %s",
CVSADM_Root, CVSADM_ROOT);
error (0, 0, "does not match command line -d %s setting",
CVSroot);
error (1, 0,
"you may wish to try the cvs command again without the -d option ");
}
}
}
#endif /* CVSADM_ROOT */
/*
* 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.
*/
#ifdef SERVER_SUPPORT
if (strcmp (command_name, "server") != 0 || CVSroot != NULL)
#endif
{
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 (!isaccessible (path, R_OK | X_OK))
{
save_errno = errno;
#ifdef CLIENT_SUPPORT
if (strchr (CVSroot, ':') == NULL)
{
#endif
error (0, 0,
"Sorry, you don't have sufficient access to %s", CVSroot);
error (1, save_errno, "%s", path);
#ifdef CLIENT_SUPPORT
}
#endif
}
(void) strcat (path, "/");
(void) strcat (path, CVSROOTADM_HISTORY);
if (isfile (path) && !isaccessible (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);
}
}
}
#ifdef SERVER_SUPPORT
if (strcmp (command_name, "server") == 0)
/* This is only used for writing into the history file. Might
be nice to have hostname and/or remote path, on the other hand
I'm not sure whether it is worth the trouble. */
strcpy (CurDir, "<remote>");
else if (!getwd (CurDir))
error (1, 0, "cannot get working directory: %s", CurDir);
#endif
#ifdef HAVE_PUTENV
/* 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 */
/* make sure we clean up on error */
#ifdef SIGHUP
(void) SIG_register (SIGHUP, main_cleanup);
(void) SIG_register (SIGHUP, Lock_Cleanup);
#endif
#ifdef SIGINT
(void) SIG_register (SIGINT, main_cleanup);
(void) SIG_register (SIGINT, Lock_Cleanup);
#endif
#ifdef SIGQUIT
(void) SIG_register (SIGQUIT, main_cleanup);
(void) SIG_register (SIGQUIT, Lock_Cleanup);
#endif
#ifdef SIGPIPE
(void) SIG_register (SIGPIPE, main_cleanup);
(void) SIG_register (SIGPIPE, Lock_Cleanup);
#endif
#ifdef SIGTERM
(void) SIG_register (SIGTERM, main_cleanup);
(void) SIG_register (SIGTERM, Lock_Cleanup);
#endif
gethostname(hostname, sizeof (hostname));
#ifdef HAVE_SETVBUF
/*
* 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
if (use_cvsrc)
read_cvsrc(&argc, &argv);
#ifdef CLIENT_SUPPORT
/* If cvsroot contains a colon, try to do it via the protocol. */
{
char *p = CVSroot == NULL ? NULL : strchr (CVSroot, ':');
if (p)
err = (*(cm->client_func)) (argc, argv);
else
err = (*(cm->func)) (argc, argv);
}
#else /* No CLIENT_SUPPORT */
err = (*(cm->func)) (argc, argv);
#endif /* No CLIENT_SUPPORT */
}
/*
* 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 const char *const *cpp;
{
(void) fprintf (stderr, *cpp++, program_name, command_name);
for (; *cpp; cpp++)
(void) fprintf (stderr, *cpp);
exit (1);
}

View file

@ -1,884 +0,0 @@
/*
* 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.4 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"
#include "save-cwd.h"
#ifndef lint
static const char rcsid[] = "$CVSid: @(#)modules.c 1.62 94/09/29 $";
USE(rcsid);
#endif
struct sortrec
{
char *modname;
char *status;
char *rest;
char *comment;
};
static int sort_order PROTO((const PTR l, const PTR r));
static void save_d PROTO((char *k, int ks, char *d, int ds));
/*
* 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;
CALLBACKPROC 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 *export_prog = NULL;
char *tag_prog = NULL;
char *update_prog = NULL;
struct saved_cwd cwd;
char line[MAXLINELEN];
int modargc;
int xmodargc;
char **modargv;
char *xmodargv[MAXFILEPERDIR];
char *value;
char *zvalue;
char *mwhere = NULL;
char *mfile = NULL;
char *spec_opt = NULL;
char xvalue[PATH_MAX];
int alias = 0;
datum key, val;
char *cp;
int c, err = 0;
#ifdef SERVER_SUPPORT
if (trace)
{
fprintf (stderr, "%c-> do_module (%s, %s, %s, %s)\n",
(server_active) ? 'S' : ' ',
mname, msg, where ? where : "",
extra_arg ? extra_arg : "");
}
#endif
/* remember where we start */
if (save_cwd (&cwd))
exit (1);
/* if this is a directory to ignore, add it to that list */
if (mname[0] == '!' && mname[1] != '\0')
{
ign_dir_add (mname+1);
return(err);
}
/* 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 = strchr (val.dptr, '#')) != NULL)
{
do
*cp-- = '\0';
while (isspace (*cp));
}
else
{
/* Always strip trailing spaces */
cp = strchr (val.dptr, '\0');
while (cp > val.dptr && isspace(*--cp))
*cp = '\0';
}
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 = strrchr (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 = strrchr (mname, '/')) != NULL && cp != mname)
{
char *slashp;
/* put the ' ' in a copy so we don't mess up the original */
value = strcpy (xvalue, mname);
slashp = strrchr (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 = strchr (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 = strchr (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 = strchr (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))
{
char nullrepos[PATH_MAX];
(void) sprintf (nullrepos, "%s/%s/%s", CVSroot,
CVSROOTADM, CVSNULLREPOS);
if (!isfile (nullrepos))
{
mode_t omask;
omask = umask (cvsumask);
(void) CVS_MKDIR (nullrepos, 0777);
(void) umask (omask);
}
if (!isdir (nullrepos))
error (1, 0, "there is no repository %s", nullrepos);
Create_Admin (".", dir,
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);
#ifdef SERVER_SUPPORT
if (server_active)
server_set_entstat (dir, nullrepos);
#endif
}
}
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 (&xmodargc, xmodargv, line);
modargc = xmodargc;
modargv = xmodargv;
/* parse the args */
optind = 1;
while ((c = 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 'e':
export_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++)
{
if (strcmp (mname, modargv[i]) == 0)
error (0, 0,
"module `%s' in modules file contains infinite loop",
mname);
else
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);
#if 0
/* FIXME: I've fixed this so that the correct arguments are called,
but now this fails because there is code below this point that
uses optarg values extracted from the arg vector. */
free_names (&xmodargc, xmodargv);
#endif
/* 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 = strchr (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 */
#ifdef SERVER_SUPPORT
if (err == 0 && !noexec && m_type == CHECKOUT && server_expanding)
{
if (checkin_prog != NULL)
server_prog (where ? where : mname, checkin_prog, PROG_CHECKIN);
if (update_prog != NULL)
server_prog (where ? where : mname, update_prog, PROG_UPDATE);
}
else
#endif
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 (restore_cwd (&cwd, NULL))
exit (1);
free_cwd (&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) ||
(m_type == EXPORT && export_prog != NULL))
{
/*
* If a relative pathname is specified as the checkout, tag
* or export 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 :
(m_type == CHECKOUT ? checkout_prog : export_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; /* Nonzero if the user is
interested in status
information as well as
module name */
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 = strchr (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 = strchr (cp, '#')) != NULL)
{
if (*--cp2 == ' ')
*cp2 = '\0';
if (*++cp == ' ')
cp++;
s_rec->comment = cp;
}
else
s_rec->comment = "";
s_count++;
}
/* Print out the module database as we know it. If STATUS is
non-zero, print out status information for each module. */
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 = 0;
wid = 0;
while ((c = getopt (argc, argv, CVSMODULE_OPTS)) != -1)
{
if (!status)
{
if (c == 'a' || c == 'l')
{
(void) printf (" -%c", c);
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);
}
free_names(&moduleargc, moduleargv);
}
}

View file

@ -1,135 +0,0 @@
/*
* 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.4 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 const char rcsid[] = "$CVSid: @(#)no_diff.c 1.39 94/10/07 $";
USE(rcsid);
#endif
int
No_Difference (file, vers, entries, repository, update_dir)
char *file;
Vers_TS *vers;
List *entries;
char *repository;
char *update_dir;
{
Node *p;
char tmp[L_tmpnam+1];
int ret;
char *ts, *options;
int retcode = 0;
char *tocvsPath;
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 0
/* Why would we want to munge the modes? And only if the timestamps
are different? And even for commands like "cvs status"???? */
if (!iswritable (file)) /* fix the modes as a side effect */
xchmod (file, 1);
#endif
tocvsPath = wrap_tocvs_process_file (file);
/* do the byte by byte compare */
if (xcmp (tocvsPath == NULL ? file : tocvsPath, tmp) == 0)
{
#if 0
/* Why would we want to munge the modes? And only if the
timestamps are different? And even for commands like
"cvs status"???? */
if (cvswrite == FALSE) /* fix the modes as a side effect */
xchmod (file, 0);
#endif
/* 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, (char *) 0);
#ifdef SERVER_SUPPORT
if (server_active)
{
/* We need to update the entries line on the client side. */
server_update_entries
(file, update_dir, repository, SERVER_UPDATED);
}
#endif
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 */
if (tocvsPath)
{
/* Need to call unlink myself because the noexec variable
* has been set to 1. */
if (trace)
(void) fprintf (stderr, "%c-> unlink (%s)\n",
#ifdef SERVER_SUPPORT
(server_active) ? 'S' : ' ',
#else
' ',
#endif
tocvsPath);
if (unlink (tocvsPath) < 0)
error (0, errno, "could not remove %s", tocvsPath);
}
}
else
{
if (update_dir[0] == '\0')
error (0, retcode == -1 ? errno : 0,
"could not check out revision %s of %s",
vers->vn_user, file);
else
error (0, retcode == -1 ? errno : 0,
"could not check out revision %s of %s/%s",
vers->vn_user, update_dir, file);
ret = -1; /* different since we couldn't tell */
}
if (trace)
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> unlink2 (%s)\n",
(server_active) ? 'S' : ' ', tmp);
#else
(void) fprintf (stderr, "-> unlink (%s)\n", tmp);
#endif
if (unlink (tmp) < 0)
error (0, errno, "could not remove %s", tmp);
free (options);
return (ret);
}

View file

@ -1,3 +1,4 @@
/* src/options.h. Generated automatically by configure. */
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
@ -54,9 +55,9 @@
/*
* 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".
* pathname if your site wants to use a particular diff. Note that unlike
* the diff used with RCS, you *must not* supply -a here (doing so will cause
* the server to generate patches which patch cannot handle in some cases).
*
* NOTE: this program is only used for the ``patch'' sub-command (and
* for ``update'' if you are using the server). The other commands
@ -65,7 +66,7 @@
*/
#ifndef DIFF
#define DIFF "/usr/bin/diff -a"
#define DIFF "diff"
#endif
/*
@ -79,23 +80,6 @@
#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
/*
* The "patch" program to run when using the CVS server and accepting
* patches across the network. Specify a full pathname if your site
@ -114,8 +98,23 @@
* 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.
* If you use the password-authenticating server, then you need to
* make sure that the server can find the RCS programs to invoke them.
* The authenticating server starts out running as root, and then
* switches to run as the appropriate user once authentication is
* complete. But no actual shell is ever started by that user, so the
* PATH environment variable may not contain the directory with the
* RCS binaries, even though if that user logged in normally, PATH
* would include the directory.
*
* One way to solve this problem is to set RCSBIN_DFLT here. An
* alternative is to make sure that root has the right directory in
* its path already. Another, probably better alternative is to
* specify -b in /etc/inetd.conf.
*
* 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 ""
@ -211,19 +210,6 @@
#define CVS_BADROOT
#endif
/*
* The "cvs admin" command allows people to get around most of the logging
* and info procedures within CVS. For exmaple, "cvs tag tagname filename"
* will perform some validity checks on the tag, while "cvs admin -Ntagname"
* will not perform those checks. For this reason, some sites may wish to
* disable the admin function completely.
*
* To disable the admin function, uncomment the lines below.
*/
#ifndef CVS_NOADMIN
/* #define CVS_NOADMIN */
#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
@ -236,20 +222,24 @@
#define CVS_DIFFDATE
#endif
/*
* define this to enable the SETXID support (see FAQ 4D.13)
*/
/* Define this to enable the SETXID support. The way to use this is
to create a group with no users in it (except perhaps cvs
administrators), set the cvs executable to setgid that group, chown
all the repository files to that group, and change all directory
permissions in the repository to 770. The last person to modify a
file will own it, but as long as directory permissions are set
right that won't matter. You'll need a system which inherits file
groups from the parent directory. I don't know how carefully this
has been inspected for security holes. */
#ifndef SETXID_SUPPORT
/* #define SETXID_SUPPORT */
#endif
/*
* The authenticated client/server is under construction. Don't
* define either of these unless you're testing them, in which case
* you're me and you already know that.
*/
/* #undef AUTH_CLIENT_SUPPORT */
/* #undef AUTH_SERVER_SUPPORT */
/* Should we build the password-authenticating client? Whether to
include the password-authenticating _server_, on the other hand, is
set in config.h. */
#define AUTH_CLIENT_SUPPORT 1
/*
* If you are working with a large remote repository and a 'cvs checkout' is
@ -265,9 +255,9 @@
* You may override the default hi/low watermarks here too.
*/
#ifndef SERVER_FLOWCONTROL
# define SERVER_FLOWCONTROL
# define SERVER_HI_WATER (2 * 1024 * 1024)
# define SERVER_LO_WATER (1 * 1024 * 1024)
#define SERVER_FLOWCONTROL
#define SERVER_HI_WATER (2 * 1024 * 1024)
#define SERVER_LO_WATER (1 * 1024 * 1024)
#endif
/* End of CVS configuration section */

View file

@ -1,171 +0,0 @@
/*
* 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.4 kit.
*/
#include "cvs.h"
#ifndef lint
static const char rcsid[] = "$CVSid: @(#)parseinfo.c 1.18 94/09/23 $";
USE(rcsid);
#endif
/*
* Parse the INFOFILE file for the specified REPOSITORY. Invoke CALLPROC for
* the first line in the file that matches the REPOSITORY, or if ALL != 0, any lines
* matching "ALL", or if no lines match, the last line matching "DEFAULT".
*
* 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;
CALLPROC callproc;
int all;
{
int err = 0;
FILE *fp_info;
char infopath[PATH_MAX];
char line[MAXLINELEN];
char *default_value = NULL;
char *expanded_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);
if (trace)
(void) fprintf (stderr, "-> ParseInfo(%s, %s, %s)\n",
infopath, srepos, all ? "ALL" : "not ALL");
/* 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 = strrchr (value, '\n')) != NULL)
*cp = '\0';
expanded_value = expand_path (value);
if (!expanded_value)
{
error (0, 0,
"Invalid environmental variable at line %d in file %s",
line_number, infofile);
continue;
}
/*
* 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 (expanded_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, expanded_value);
else
error(0, 0, "Keyword `ALL' is ignored at line %d in %s file",
line_number, infofile);
continue;
}
if (callback_done)
/* only first matching, plus "ALL"'s */
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, expanded_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);
if (expanded_value != NULL)
free (expanded_value);
return (err);
}

View file

@ -1,615 +0,0 @@
/*
* 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.4 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"
#include "getline.h"
#ifndef lint
static const char rcsid[] = "$CVSid: @(#)patch.c 1.57 94/09/30 $";
USE(rcsid);
#endif
static RETSIGTYPE patch_cleanup PROTO((void));
static Dtype patch_dirproc PROTO((char *dir, char *repos, char *update_dir));
static int patch_fileproc PROTO((char *file, char *update_dir, char *repository,
List * entries, List * srcfiles));
static int patch_proc PROTO((int *pargc, char **argv, char *xwhere,
char *mwhere, char *mfile, int shorten,
int local_specified, char *mname, char *msg));
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 const char *const patch_usage[] =
{
"Usage: %s %s [-fl] [-c|-u] [-s|-t] [-V %%d]\n",
" -r rev|-D date [-r rev2 | -D date2] modules...\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 = getopt (argc, argv, "V:k:cuftsQqlRD:r:")) != -1)
{
switch (c)
{
case 'Q':
case 'q':
#ifdef SERVER_SUPPORT
/* The CVS 1.5 client sends these options (in addition to
Global_option requests), so we must ignore them. */
if (!server_active)
#endif
error (1, 0,
"-q or -Q must be specified before \"%s\"",
command_name);
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 ("");
#ifdef CLIENT_SUPPORT
if (client_active)
{
/* We're the client side. Fire up the remote server. */
start_server ();
ign_setup ();
if (local)
send_arg("-l");
if (force_tag_match)
send_arg("-f");
if (toptwo_diffs)
send_arg("-t");
if (patch_short)
send_arg("-s");
if (unidiff)
send_arg("-u");
if (rev1)
option_with_arg ("-r", rev1);
if (date1)
client_senddate (date1);
if (rev2)
option_with_arg ("-r", rev2);
if (date2)
client_senddate (date2);
if (options[0] != '\0')
send_arg (options);
{
int i;
for (i = 0; i < argc; ++i)
send_arg (argv[i]);
}
if (fprintf (to_server, "rdiff\n") < 0)
error (1, errno, "writing to server");
return get_responses_and_close ();
}
#endif
/* clean up if we get a signal */
#ifdef SIGHUP
(void) SIG_register (SIGHUP, patch_cleanup);
#endif
#ifdef SIGINT
(void) SIG_register (SIGINT, patch_cleanup);
#endif
#ifdef SIGQUIT
(void) SIG_register (SIGQUIT, patch_cleanup);
#endif
#ifdef SIGPIPE
(void) SIG_register (SIGPIPE, patch_cleanup);
#endif
#ifdef SIGTERM
(void) SIG_register (SIGTERM, patch_cleanup);
#endif
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 = strrchr (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, (FILESDONEPROC) NULL, patch_dirproc,
(DIRLEAVEPROC) NULL, *pargc - 1, argv + 1, local,
which, 0, 1, where, 1, 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;
{
struct utimbuf t;
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, *line2;
size_t line1_chars_allocated;
size_t line2_chars_allocated;
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, 0);
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, 0);
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)
#ifdef DEATH_SUPPORT
{
(void) printf ("%s is removed; not included in ", rcs);
if (rev2 != NULL)
(void) printf ("release tag %s", rev2);
else if (date2 != NULL)
(void) printf ("release date %s", date2);
else
(void) printf ("current release");
(void) printf ("\n");
}
#else
(void) printf ("%s is removed; not included in release %s\n",
rcs, rev2 ? rev2 : date2);
#endif
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;
}
memset ((char *) &t, 0, sizeof (t));
if ((t.actime = t.modtime = RCS_getrevtime (rcsfile, vers_tag,
(char *) 0, 0)) != -1)
(void) utime (tmpfile1, &t);
}
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;
}
if ((t.actime = t.modtime = RCS_getrevtime (rcsfile, vers_head,
(char *) 0, 0)) != -1)
(void) utime (tmpfile2, &t);
}
run_setup ("%s -%c", DIFF, unidiff ? 'u' : 'c');
run_arg (tmpfile1);
run_arg (tmpfile2);
line1 = NULL;
line1_chars_allocated = 0;
line2 = NULL;
line2_chars_allocated = 0;
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.
*/
/* Output an "Index:" line for patch to use */
(void) fflush (stdout);
if (update_dir[0])
(void) printf ("Index: %s/%s\n", update_dir, file);
else
(void) printf ("Index: %s\n", file);
(void) fflush (stdout);
fp = open_file (tmpfile3, "r");
if (getline (&line1, &line1_chars_allocated, fp) < 0 ||
getline (&line2, &line2_chars_allocated, fp) < 0)
{
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 = strchr (line1, '\t')) == NULL ||
(cp2 = strchr (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 = strchr (line1, '\t')) == NULL ||
(cp2 = strchr (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 = strrchr (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);
/* spew the rest of the diff out */
while (getline (&line1, &line1_chars_allocated, fp) >= 0)
(void) fputs (line1, stdout);
(void) fclose (fp);
break;
default:
error (0, 0, "diff failed for %s", rcs);
}
out:
if (line1)
free (line1);
if (line2)
free (line2);
(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 RETSIGTYPE
patch_cleanup ()
{
if (tmpfile1[0] != '\0')
(void) unlink_file (tmpfile1);
if (tmpfile2[0] != '\0')
(void) unlink_file (tmpfile2);
if (tmpfile3[0] != '\0')
(void) unlink_file (tmpfile3);
}

View file

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

File diff suppressed because it is too large Load diff

View file

@ -1,107 +0,0 @@
/* $CVSid: @(#)rcs.h 1.18 94/09/23 $ */
/*
* 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.4 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 RCSPAT "*,v"
#define RCSHEAD "head"
#define RCSBRANCH "branch"
#define RCSSYMBOLS "symbols"
#define RCSDATE "date"
#define RCSDESC "desc"
#define RCSEXPAND "expand"
/* Used by the version of death support which results if you define
DEATH_SUPPORT and not DEATH_STATE. Requires a hacked up RCS. Considered
obsolete. */
#define RCSDEAD "dead"
#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 */
#define PARTIAL 0x4 /* RCS file not completly parsed */
struct rcsnode
{
int refcount;
int flags;
char *path;
char *head;
char *branch;
char *symbols_data;
char *expand;
List *symbols;
List *versions;
List *dates;
};
typedef struct rcsnode RCSNode;
struct rcsversnode
{
char *version;
char *date;
char *next;
int dead;
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
*/
List *RCS_parsefiles PROTO((List * files, char *xrepos));
RCSNode *RCS_parse PROTO((const char *file, const char *repos));
RCSNode *RCS_parsercsfile PROTO((char *rcsfile));
char *RCS_check_kflag PROTO((const char *arg));
char *RCS_getdate PROTO((RCSNode * rcs, char *date, int force_tag_match));
char *RCS_gettag PROTO((RCSNode * rcs, char *symtag, int force_tag_match,
int return_both));
char *RCS_getversion PROTO((RCSNode * rcs, char *tag, char *date,
int force_tag_match, int return_both));
char *RCS_magicrev PROTO((RCSNode *rcs, char *rev));
int RCS_isbranch PROTO((char *file, char *rev, List *srcfiles));
int RCS_nodeisbranch PROTO((char *rev, RCSNode *rcs));
char *RCS_whatbranch PROTO((char *file, char *tag, List *srcfiles));
char *RCS_head PROTO((RCSNode * rcs));
int RCS_datecmp PROTO((char *date1, char *date2));
time_t RCS_getrevtime PROTO((RCSNode * rcs, char *rev, char *date, int fudge));
List *RCS_symbols PROTO((RCSNode *rcs));
void RCS_check_tag PROTO((const char *tag));
void freercsnode PROTO((RCSNode ** rnodep));
void RCS_addnode PROTO((const char *file, RCSNode *rcs, List *list));
char *RCS_getbranch PROTO((RCSNode * rcs, char *tag, int force_tag_match));
#ifdef DEATH_SUPPORT
int RCS_isdead PROTO((RCSNode *, const char *));
#endif

View file

@ -1,102 +0,0 @@
/*
* 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.4 kit.
*
* The functions in this file provide an interface for performing
* operations directly on RCS files.
*/
#include "cvs.h"
int
RCS_settag(path, tag, rev)
const char *path;
const char *tag;
const char *rev;
{
run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, tag, rev);
run_arg (path);
return run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
}
/* NOERR is 1 to suppress errors--FIXME it would
be better to avoid the errors or some cleaner solution. */
int
RCS_deltag(path, tag, noerr)
const char *path;
const char *tag;
int noerr;
{
run_setup ("%s%s -q -N%s", Rcsbin, RCS, tag);
run_arg (path);
return run_exec (RUN_TTY, RUN_TTY, noerr ? DEVNULL : RUN_TTY, RUN_NORMAL);
}
/* set RCS branch to REV */
int
RCS_setbranch(path, rev)
const char *path;
const char *rev;
{
run_setup ("%s%s -q -b%s", Rcsbin, RCS, rev ? rev : "");
run_arg (path);
return run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
}
/* Lock revision REV. NOERR is 1 to suppress errors--FIXME it would
be better to avoid the errors or some cleaner solution. */
int
RCS_lock(path, rev, noerr)
const char *path;
const char *rev;
int noerr;
{
run_setup ("%s%s -q -l%s", Rcsbin, RCS, rev ? rev : "");
run_arg (path);
return run_exec (RUN_TTY, RUN_TTY, noerr ? DEVNULL : RUN_TTY, RUN_NORMAL);
}
/* Unlock revision REV. NOERR is 1 to suppress errors--FIXME it would
be better to avoid the errors or some cleaner solution. */
int
RCS_unlock(path, rev, noerr)
const char *path;
const char *rev;
int noerr;
{
run_setup ("%s%s -q -u%s", Rcsbin, RCS, rev ? rev : "");
run_arg (path);
return run_exec (RUN_TTY, RUN_TTY, noerr ? DEVNULL : RUN_TTY, RUN_NORMAL);
}
/* Merge revisions REV1 and REV2. */
int
RCS_merge(path, options, rev1, rev2)
const char *path;
const char *options;
const char *rev1;
const char *rev2;
{
int status;
/* XXX - Do merge by hand instead of using rcsmerge, due to -k handling */
run_setup ("%s%s %s -r%s -r%s %s", Rcsbin, RCS_RCSMERGE,
options, rev1, rev2, path);
status = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
#ifndef HAVE_RCS5
if (status == 0)
{
/* Run GREP to see if there appear to be conflicts in the file */
run_setup ("%s", GREP);
run_arg (RCS_MERGE_PAT);
run_arg (path);
status = (run_exec (RUN_TTY, DEVNULL, RUN_TTY, RUN_NORMAL) == 0);
}
#endif
return status;
}

View file

@ -1,646 +0,0 @@
/*
* 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.4 kit.
*
* General recursion handler
*
*/
#include "cvs.h"
#include "save-cwd.h"
#ifndef lint
static const char rcsid[] = "$CVSid: @(#)recurse.c 1.31 94/09/30 $";
USE(rcsid);
#endif
static int do_dir_proc PROTO((Node * p, void *closure));
static int do_file_proc PROTO((Node * p, void *closure));
static void addlist PROTO((List ** listp, char *key));
static int unroll_files_proc PROTO((Node *p, void *closure));
static void addfile PROTO((List **listp, char *dir, char *file));
/*
* Local static versions eliminates the need for globals
*/
static FILEPROC fileproc;
static FILESDONEPROC filesdoneproc;
static DIRENTPROC direntproc;
static DIRLEAVEPROC 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; /* holds list of files on which to operate */
static List *dirlist = NULL; /* holds list of directories on which to operate */
struct recursion_frame {
FILEPROC fileproc;
FILESDONEPROC filesdoneproc;
DIRENTPROC direntproc;
DIRLEAVEPROC dirleaveproc;
Dtype flags;
int which;
int aflag;
int readlock;
int dosrcs;
};
/*
* Called to start a recursive command.
*
* Command line arguments dictate the directories and files on which
* we operate. In the special case of no arguments, we default to
* ".".
*
* The general algorithm is as follows.
*/
int
start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc,
argc, argv, local, which, aflag, readlock,
update_preload, dosrcs, wd_is_repos)
FILEPROC fileproc;
FILESDONEPROC filesdoneproc;
DIRENTPROC direntproc;
DIRLEAVEPROC dirleaveproc;
int argc;
char **argv;
int local;
int which;
int aflag;
int readlock;
char *update_preload;
int dosrcs;
int wd_is_repos; /* Set if caller has already cd'd to the repository */
{
int i, err = 0;
Dtype flags;
List *files_by_dir = NULL;
struct recursion_frame frame;
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)
{
Entries_Close (entries);
entries = NULL;
}
if (srcfiles)
dellist (&srcfiles);
if (filelist)
dellist (&filelist); /* FIXME-krp: no longer correct. */
/* FIXME-krp: clean up files_by_dir */
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))
dirlist = Find_Dirs ((char *) NULL, W_LOCAL);
else
addlist (&dirlist, ".");
err += do_recursion (fileproc, filesdoneproc, direntproc,
dirleaveproc, flags, which, aflag,
readlock, dosrcs);
return(err);
}
/*
* 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.
*
* explicitly named directories are stored in dirlist.
* explicitly named files are stored in filelist.
* other possibility is named entities whicha are not currently in
* the working directory.
*/
for (i = 0; i < argc; i++)
{
/* if this argument is a directory, then add it to the list of
directories. */
if (!wrap_name_has (argv[i], WRAP_TOCVS) && isdir (argv[i]))
addlist (&dirlist, argv[i]);
else
{
/* otherwise, split argument into directory and component names. */
char *dir;
char *comp;
char tmp[PATH_MAX];
char *file_to_try;
dir = xstrdup (argv[i]);
if ((comp = strrchr (dir, '/')) == NULL)
{
/* no dir component. What we have is an implied "./" */
comp = dir;
dir = xstrdup(".");
}
else
{
char *p = comp;
*p++ = '\0';
comp = xstrdup (p);
}
/* if this argument exists as a file in the current
working directory tree, then add it to the files list. */
if (wd_is_repos)
{
/* If doing rtag, we've done a chdir to the repository. */
sprintf (tmp, "%s%s", argv[i], RCSEXT);
file_to_try = tmp;
}
else
file_to_try = argv[i];
if(isfile(file_to_try))
addfile (&files_by_dir, dir, comp);
else if (isdir (dir))
{
if (isdir (CVSADM))
{
/* otherwise, look for it in the repository. */
char *save_update_dir;
char *repos;
/* save & set (aka push) update_dir */
save_update_dir = xstrdup (update_dir);
if (*update_dir != '\0')
(void) strcat (update_dir, "/");
(void) strcat (update_dir, dir);
/* look for it in the repository. */
repos = Name_Repository (dir, update_dir);
(void) sprintf (tmp, "%s/%s", repos, comp);
free (repos);
if (!wrap_name_has (comp, WRAP_TOCVS) && isdir(tmp))
addlist (&dirlist, argv[i]);
else
addfile (&files_by_dir, dir, comp);
(void) sprintf (update_dir, "%s", save_update_dir);
free (save_update_dir);
}
else
addfile (&files_by_dir, dir, comp);
}
else
error (1, 0, "no such directory `%s'", dir);
free (dir);
free (comp);
}
}
/* At this point we have looped over all named arguments and built
a coupla lists. Now we unroll the lists, setting up and
calling do_recursion. */
frame.fileproc = fileproc;
frame.filesdoneproc = filesdoneproc;
frame.direntproc = direntproc;
frame.dirleaveproc = dirleaveproc;
frame.flags = flags;
frame.which = which;
frame.aflag = aflag;
frame.readlock = readlock;
frame.dosrcs = dosrcs;
err += walklist (files_by_dir, unroll_files_proc, (void *) &frame);
/* then do_recursion on the dirlist. */
if (dirlist != NULL)
err += do_recursion (frame.fileproc, frame.filesdoneproc,
frame.direntproc, frame.dirleaveproc,
frame.flags, frame.which, frame.aflag,
frame.readlock, frame.dosrcs);
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)
FILEPROC xfileproc;
FILESDONEPROC xfilesdoneproc;
DIRENTPROC xdirentproc;
DIRLEAVEPROC 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;
#if defined(SERVER_SUPPORT) && defined(SERVER_FLOWCONTROL)
/*
* Now would be a good time to check to see if we need to stop
* generating data, to give the buffers a chance to drain to the
* remote client. We should not have locks active at this point.
*/
if (server_active
/* If there are writelocks around, we cannot pause here. */
&& (readlock || noexec))
server_pause_check();
#endif
/*
* Fill in repository with the current repository
*/
if (which & W_LOCAL)
{
if (isdir (CVSADM))
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 = Entries_Open (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, NULL);
/* unlock it */
if (readlock)
Lock_Cleanup ();
/* clean up */
dellist (&filelist);
dellist (&srcfiles);
Entries_Close (entries);
entries = NULL;
}
/* 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, NULL);
#ifdef notdef
else if (dirleaveproc != NULL)
err += dirleaveproc(".", err, ".");
#endif
dellist (&dirlist);
/* free the saved copy of the pointer if necessary */
if (srepository)
{
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, closure)
Node *p;
void *closure;
{
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, closure)
Node *p;
void *closure;
{
char *dir = p->key;
char newrepos[PATH_MAX];
List *sdirlist;
char *srepository;
char *cp;
Dtype dir_return = R_PROCESS;
int stripped_dot = 0;
int err = 0;
struct saved_cwd cwd;
/* 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 (save_cwd (&cwd))
exit (1);
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 (restore_cwd (&cwd, NULL))
exit (1);
free_cwd (&cwd);
dirlist = sdirlist;
repository = srepository;
}
/* put back update_dir */
if ((cp = strrchr (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);
if (addnode (*listp, p) != 0)
freenode (p);
}
static void
addfile (listp, dir, file)
List **listp;
char *dir;
char *file;
{
Node *n;
/* add this dir. */
addlist (listp, dir);
n = findnode (*listp, dir);
if (n == NULL)
{
error (1, 0, "can't find recently added dir node `%s' in start_recursion.",
dir);
}
n->type = DIRS;
addlist ((List **) &n->data, file);
return;
}
static int
unroll_files_proc (p, closure)
Node *p;
void *closure;
{
Node *n;
struct recursion_frame *frame = (struct recursion_frame *) closure;
int err = 0;
List *save_dirlist;
char *save_update_dir = NULL;
struct saved_cwd cwd;
/* if this dir was also an explicitly named argument, then skip
it. We'll catch it later when we do dirs. */
n = findnode (dirlist, p->key);
if (n != NULL)
return (0);
/* otherwise, call dorecusion for this list of files. */
filelist = (List *) p->data;
save_dirlist = dirlist;
dirlist = NULL;
if (strcmp(p->key, ".") != 0)
{
if (save_cwd (&cwd))
exit (1);
if (chdir (p->key) < 0)
error (1, errno, "could not chdir to %s", p->key);
save_update_dir = xstrdup (update_dir);
if (*update_dir != '\0')
(void) strcat (update_dir, "/");
(void) strcat (update_dir, p->key);
}
err += do_recursion (frame->fileproc, frame->filesdoneproc,
frame->direntproc, frame->dirleaveproc,
frame->flags, frame->which, frame->aflag,
frame->readlock, frame->dosrcs);
if (save_update_dir != NULL)
{
(void) strcpy (update_dir, save_update_dir);
free (save_update_dir);
if (restore_cwd (&cwd, NULL))
exit (1);
free_cwd (&cwd);
}
dirlist = save_dirlist;
filelist = NULL;
return(err);
}

View file

@ -1,259 +0,0 @@
/*
* 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 const char rcsid[] = "$CVSid: @(#)release.c 1.23 94/09/21 $";
USE(rcsid);
#endif
static void release_delete PROTO((char *dir));
static const char *const release_usage[] =
{
"Usage: %s %s [-d] modules...\n",
"\t-d\tDelete the given directory.\n",
NULL
};
static short delete;
int
release (argc, argv)
int argc;
char **argv;
{
FILE *fp;
register int i, c;
char *repository, *srepos;
char line[PATH_MAX], update_cmd[PATH_MAX];
char *thisarg;
int arg_start_idx;
#ifdef SERVER_SUPPORT
if (!server_active)
{
#endif /* SERVER_SUPPORT */
if (argc == -1)
usage (release_usage);
optind = 1;
while ((c = getopt (argc, argv, "Qdq")) != -1)
{
switch (c)
{
case 'Q':
case 'q':
#ifdef SERVER_SUPPORT
/* The CVS 1.5 client sends these options (in addition to
Global_option requests), so we must ignore them. */
if (!server_active)
#endif
error (1, 0,
"-q or -Q must be specified before \"%s\"",
command_name);
break;
case 'd':
delete++;
break;
case '?':
default:
usage (release_usage);
break;
}
}
argc -= optind;
argv += optind;
#ifdef SERVER_SUPPORT
}
#endif /* SERVER_SUPPORT */
/* We're going to run "cvs -n -q update" and check its output; if
* the output is sufficiently unalarming, then we release with no
* questions asked. Else we prompt, then maybe release.
*/
/* Construct the update command. */
sprintf (update_cmd, "%s -n -q -d %s update",
program_path, CVSroot);
#ifdef CLIENT_SUPPORT
/* Start the server; we'll close it after looping. */
if (client_active)
{
start_server ();
ign_setup ();
}
#endif /* CLIENT_SUPPORT */
/* If !server_active, we already skipped over argv[0] in the "argc
-= optind;" statement above. But if server_active, we need to
skip it now. */
#ifdef SERVER_SUPPORT
if (server_active)
arg_start_idx = 1;
else
arg_start_idx = 0;
#endif /* SERVER_SUPPORT */
for (i = arg_start_idx; i < argc; i++)
{
thisarg = argv[i];
#ifdef SERVER_SUPPORT
if (server_active)
{
/* Just log the release -- all the interesting stuff happened
* on the client.
*/
history_write ('F', thisarg, "", thisarg, ""); /* F == Free */
}
else
{
#endif /* SERVER_SUPPORT */
/*
* 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 (thisarg))
{
if (chdir (thisarg) < 0)
{
if (!really_quiet)
error (0, 0, "can't chdir to: %s", thisarg);
continue;
}
if (!isdir (CVSADM))
{
if (!really_quiet)
error (0, 0, "no repository module: %s", thisarg);
continue;
}
}
else
{
if (!really_quiet)
error (0, 0, "no such directory: %s", thisarg);
continue;
}
repository = Name_Repository ((char *) NULL, (char *) NULL);
srepos = Short_Repository (repository);
if (!really_quiet)
{
/* The "release" command piggybacks on "update", which
* does the real work of finding out if anything is not
* up-to-date with the repository. Then "release" prompts
* the user, telling her how many files have been
* modified, and asking if she still wants to do the
* release.
*/
fp = Popen (update_cmd, "r");
c = 0;
while (fgets (line, sizeof (line), fp))
{
if (strchr ("MARCZ", *line))
c++;
(void) printf (line);
}
/* If the update exited with an error, then we just want to
* complain and go on to the next arg. Especially, we do
* not want to delete the local copy, since it's obviously
* not what the user thinks it is.
*/
if ((pclose (fp)) != 0)
{
error (0, 0, "unable to release `%s'", thisarg);
continue;
}
(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) " : "", thisarg);
c = !yesno ();
if (c) /* "No" */
{
(void) fprintf (stderr, "** `%s' aborted by user choice.\n",
command_name);
free (repository);
continue;
}
}
#ifdef CLIENT_SUPPORT
if (client_active)
{
if (fprintf (to_server, "Argument %s\n", thisarg) < 0)
error (1, errno, "writing to server");
if (fprintf (to_server, "release\n") < 0)
error (1, errno, "writing to server");
}
else
{
#endif /* CLIENT_SUPPORT */
history_write ('F', thisarg, "", thisarg, ""); /* F == Free */
#ifdef CLIENT_SUPPORT
} /* else client not active */
#endif /* CLIENT_SUPPORT */
free (repository);
if (delete) release_delete (thisarg);
#ifdef CLIENT_SUPPORT
if (client_active)
return get_responses_and_close ();
else
#endif /* CLIENT_SUPPORT */
return (0);
#ifdef SERVER_SUPPORT
} /* else server not active */
#endif /* SERVER_SUPPORT */
} /* `for' loop */
return (0);
}
/* We want to "rm -r" the working directory, 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;
}
/*
* XXX - shouldn't this just delete the CVS-controlled files and, perhaps,
* the files that would normally be ignored and leave everything else?
*/
run_setup ("%s -fr", RM);
run_arg (dir);
if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
error (0, retcode == -1 ? errno : 0,
"deletion of module %s failed.", dir);
}

View file

@ -1,213 +0,0 @@
/*
* 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.4 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 const char rcsid[] = "$CVSid: @(#)remove.c 1.39 94/10/07 $";
USE(rcsid);
#endif
static int remove_fileproc PROTO((char *file, char *update_dir,
char *repository, List *entries,
List *srcfiles));
static Dtype remove_dirproc PROTO((char *dir, char *repos, char *update_dir));
static int force;
static int local;
static int removed_files;
static int existing_files;
static const char *const remove_usage[] =
{
"Usage: %s %s [-flR] [files...]\n",
"\t-f\tDelete the file before removing it.\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 = getopt (argc, argv, "flR")) != -1)
{
switch (c)
{
case 'f':
force = 1;
break;
case 'l':
local = 1;
break;
case 'R':
local = 0;
break;
case '?':
default:
usage (remove_usage);
break;
}
}
argc -= optind;
argv += optind;
wrap_setup ();
#ifdef CLIENT_SUPPORT
if (client_active) {
start_server ();
ign_setup ();
if (local)
send_arg("-l");
send_files (argc, argv, local, 0);
if (fprintf (to_server, "remove\n") < 0)
error (1, errno, "writing to server");
return get_responses_and_close ();
}
#endif
/* 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, 0);
if (removed_files)
error (0, 0, "use '%s commit' to remove %s permanently", program_name,
(removed_files == 1) ? "this file" : "these files");
if (existing_files)
error (0, 0,
((existing_files == 1) ?
"%d file exists; use `%s' to remove it first" :
"%d files exist; use `%s' to remove them first"),
existing_files, 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;
if (force)
{
if (!noexec)
{
if (unlink (file) < 0 && ! existence_error (errno))
{
if (update_dir[0] == '\0')
error (0, errno, "unable to remove %s", file);
else
error (0, errno, "unable to remove %s/%s", update_dir,
file);
}
}
/* else FIXME should probably act as if the file doesn't exist
in doing the following checks. */
}
vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL,
file, 0, 0, entries, srcfiles);
if (vers->ts_user != NULL)
{
existing_files++;
if (!quiet)
error (0, 0, "file `%s' still in working directory", file);
}
else if (vers->vn_user == NULL)
{
if (!quiet)
error (0, 0, "nothing known about `%s'", file);
}
else 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 ,t file for it and scratch it from the
* entries file. */
Scratch_Entry (entries, file);
(void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_LOG);
(void) unlink_file (fname);
if (!quiet)
error (0, 0, "removed `%s'", file);
#ifdef SERVER_SUPPORT
if (server_active)
server_checked_in (file, update_dir, repository);
#endif
}
else if (vers->vn_user[0] == '-')
{
if (!quiet)
error (0, 0, "file `%s' already scheduled for removal", file);
}
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, vers->ts_conflict);
if (!quiet)
error (0, 0, "scheduling `%s' for removal", file);
removed_files++;
#ifdef SERVER_SUPPORT
if (server_active)
server_checked_in (file, update_dir, repository);
#endif
}
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);
}

View file

@ -1,147 +0,0 @@
/*
* 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.4 kit.
*
* Name of Repository
*
* Determine the name of the RCS repository and sets "Repository" accordingly.
*/
#include "cvs.h"
#ifndef lint
static const char rcsid[] = "$CVSid: @(#)repos.c 1.32 94/09/23 $";
USE(rcsid);
#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 *cp;
if (update_dir && *update_dir)
xupdate_dir = update_dir;
else
xupdate_dir = ".";
if (dir != NULL)
(void) sprintf (cvsadm, "%s/%s", dir, CVSADM);
else
(void) strcpy (cvsadm, CVSADM);
/* sanity checks */
if (!isdir (cvsadm))
{
error (0, 0, "in directory %s:", xupdate_dir);
error (1, 0, "there is no version here; do '%s checkout' first",
program_name);
}
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 = strrchr (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 (! isabsolute(repos))
{
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);
}
#ifdef CLIENT_SUPPORT
if (!client_active && !isdir (repos))
#else
if (!isdir (repos))
#endif
{
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 */
/* And skip leading '/' in rep, in case CVSroot ended with '/'. */
if (strncmp (CVSroot, repository, strlen (CVSroot)) == 0)
{
char *rep = repository + strlen (CVSroot);
return (*rep == '/') ? rep+1 : rep;
}
else
return (repository);
}

View file

@ -1,182 +0,0 @@
/*
* Copyright (c) 1992, Mark D. Baushke
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.4 kit.
*
* Name of Root
*
* Determine the path to the CVSROOT and set "Root" accordingly.
* If this looks like of modified clone of Name_Repository() in
* repos.c, it is...
*/
#include "cvs.h"
#ifndef lint
static const char rcsid[] = "$CVSid: @(#)root.c,v 1.2 1994/09/15 05:32:17 zoo Exp";
USE(rcsid);
#endif
char *
Name_Root(dir, update_dir)
char *dir;
char *update_dir;
{
FILE *fpin;
char *ret, *xupdate_dir;
char root[PATH_MAX];
char tmp[PATH_MAX];
char cvsadm[PATH_MAX];
char *cp;
if (update_dir && *update_dir)
xupdate_dir = update_dir;
else
xupdate_dir = ".";
if (dir != NULL)
{
(void) sprintf (cvsadm, "%s/%s", dir, CVSADM);
(void) sprintf (tmp, "%s/%s", dir, CVSADM_ROOT);
}
else
{
(void) strcpy (cvsadm, CVSADM);
(void) strcpy (tmp, CVSADM_ROOT);
}
/*
* Do not bother looking for a readable file if there is no cvsadm
* directory present.
*
* It is possible that not all repositories will have a CVS/Root
* file. This is ok, but the user will need to specify -d
* /path/name or have the environment variable CVSROOT set in
* order to continue.
*/
if ((!isdir (cvsadm)) || (!isreadable (tmp)))
{
if (CVSroot == NULL)
{
error (0, 0, "in directory %s:", xupdate_dir);
error (0, 0, "must set the CVSROOT environment variable");
error (0, 0, "or specify the '-d' option to %s.", program_name);
}
return (NULL);
}
/*
* The assumption here is that the CVS Root is always contained in the
* first line of the "Root" file.
*/
fpin = open_file (tmp, "r");
if (fgets (root, PATH_MAX, fpin) == NULL)
{
error (0, 0, "in directory %s:", xupdate_dir);
error (0, errno, "cannot read %s", CVSADM_ROOT);
error (0, 0, "please correct this problem");
return (NULL);
}
(void) fclose (fpin);
if ((cp = strrchr (root, '\n')) != NULL)
*cp = '\0'; /* strip the newline */
/*
* root now contains a candidate for CVSroot. It must be an
* absolute pathname
*/
#ifdef CLIENT_SUPPORT
/* It must specify a server via remote CVS or be an absolute pathname. */
if ((strchr (root, ':') == NULL)
&& ! isabsolute (root))
#else
if (root[0] != '/')
#endif
{
error (0, 0, "in directory %s:", xupdate_dir);
error (0, 0,
"ignoring %s because it does not contain an absolute pathname.",
CVSADM_ROOT);
return (NULL);
}
#ifdef CLIENT_SUPPORT
if ((strchr (root, ':') == NULL) && !isdir (root))
#else
if (!isdir (root))
#endif
{
error (0, 0, "in directory %s:", xupdate_dir);
error (0, 0,
"ignoring %s because it specifies a non-existent repository %s",
CVSADM_ROOT, root);
return (NULL);
}
/* allocate space to return and fill it in */
strip_path (root);
ret = xstrdup (root);
return (ret);
}
/*
* Returns non-zero if the two directories have the same stat values
* which indicates that they are really the same directories.
*/
int
same_directories (dir1, dir2)
char *dir1;
char *dir2;
{
struct stat sb1;
struct stat sb2;
int ret;
if (stat (dir1, &sb1) < 0)
return (0);
if (stat (dir2, &sb2) < 0)
return (0);
ret = 0;
if ( (memcmp( &sb1.st_dev, &sb2.st_dev, sizeof(dev_t) ) == 0) &&
(memcmp( &sb1.st_ino, &sb2.st_ino, sizeof(ino_t) ) == 0))
ret = 1;
return (ret);
}
/*
* Write the CVS/Root file so that the environment variable CVSROOT
* and/or the -d option to cvs will be validated or not necessary for
* future work.
*/
void
Create_Root (dir, rootdir)
char *dir;
char *rootdir;
{
FILE *fout;
char tmp[PATH_MAX];
if (noexec)
return;
/* record the current cvs root */
if (rootdir != NULL)
{
if (dir != NULL)
(void) sprintf (tmp, "%s/%s", dir, CVSADM_ROOT);
else
(void) strcpy (tmp, CVSADM_ROOT);
fout = open_file (tmp, "w+");
if (fprintf (fout, "%s\n", rootdir) < 0)
error (1, errno, "write to %s failed", tmp);
if (fclose (fout) == EOF)
error (1, errno, "cannot close %s", tmp);
}
}

View file

@ -1,692 +0,0 @@
/*
* 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.4 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 const char rcsid[] = "$CVSid: @(#)rtag.c 1.61 94/09/30 $";
USE(rcsid);
#endif
static int check_fileproc PROTO((char *file, char *update_dir,
char *repository, List * entries,
List * srcfiles));
static int check_filesdoneproc PROTO((int err, char *repos, char *update_dir));
static int pretag_proc PROTO((char *repository, char *filter));
static void masterlist_delproc PROTO((Node *p));
static void tag_delproc PROTO((Node *p));
static int pretag_list_proc PROTO((Node *p, void *closure));
static Dtype rtag_dirproc PROTO((char *dir, char *repos, char *update_dir));
static int rtag_fileproc PROTO((char *file, char *update_dir,
char *repository, List * entries,
List * srcfiles));
static int rtag_proc PROTO((int *pargc, char **argv, char *xwhere,
char *mwhere, char *mfile, int shorten,
int local_specified, char *mname, char *msg));
static int rtag_delete PROTO((RCSNode *rcsfile));
struct tag_info
{
Ctype status;
char *rev;
char *tag;
char *options;
};
struct master_lists
{
List *tlist;
};
static List *mtlist;
static List *tlist;
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 int force_tag_move; /* don't move existing tags by default */
static const char *const rtag_usage[] =
{
"Usage: %s %s [-aflRnF] [-b] [-d] [-r tag|-D date] tag modules...\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-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",
"\t-F\tMove tag if it already exists\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 = getopt (argc, argv, "FanfQqlRdbr:D:")) != -1)
{
switch (c)
{
case 'a':
attic_too = 1;
break;
case 'n':
run_module_prog = 0;
break;
case 'Q':
case 'q':
#ifdef SERVER_SUPPORT
/* The CVS 1.5 client sends these options (in addition to
Global_option requests), so we must ignore them. */
if (!server_active)
#endif
error (1, 0,
"-q or -Q must be specified before \"%s\"",
command_name);
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 'F':
force_tag_move = 1;
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);
#ifdef CLIENT_SUPPORT
if (client_active)
{
/* We're the client side. Fire up the remote server. */
start_server ();
ign_setup ();
if (local)
send_arg("-l");
if (delete)
send_arg("-d");
if (branch_mode)
send_arg("-b");
if (force_tag_move)
send_arg("-F");
if (run_module_prog)
send_arg("-n");
if (attic_too)
send_arg("-a");
if (numtag)
option_with_arg ("-r", numtag);
if (date)
client_senddate (date);
send_arg (symtag);
{
int i;
for (i = 0; i < argc; ++i)
send_arg (argv[i]);
}
if (fprintf (to_server, "rtag\n") < 0)
error (1, errno, "writing to server");
return get_responses_and_close ();
}
#endif
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 = strrchr (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;
/* check to make sure they are authorized to tag all the
specified files in the repository */
mtlist = getlist();
err = start_recursion (check_fileproc, check_filesdoneproc,
(DIRENTPROC) NULL, (DIRLEAVEPROC) NULL,
*pargc - 1, argv + 1, local, which, 0, 1,
where, 1, 1);
if (err)
{
error (1, 0, "correct the above errors first!");
}
/* start the recursion processor */
err = start_recursion (rtag_fileproc, (FILESDONEPROC) NULL, rtag_dirproc,
(DIRLEAVEPROC) NULL, *pargc - 1, argv + 1, local,
which, 0, 1, where, 1, 1);
dellist(&mtlist);
return (err);
}
/* check file that is to be tagged */
/* All we do here is add it to our list */
static int
check_fileproc(file, update_dir, repository, entries, srcfiles)
char *file;
char *update_dir;
char *repository;
List * entries;
List * srcfiles;
{
char *xdir;
Node *p;
Vers_TS *vers;
if (update_dir[0] == '\0')
xdir = ".";
else
xdir = update_dir;
if ((p = findnode (mtlist, xdir)) != NULL)
{
tlist = ((struct master_lists *) p->data)->tlist;
}
else
{
struct master_lists *ml;
tlist = getlist ();
p = getnode ();
p->key = xstrdup (xdir);
p->type = UPDATE;
ml = (struct master_lists *)
xmalloc (sizeof (struct master_lists));
ml->tlist = tlist;
p->data = (char *) ml;
p->delproc = masterlist_delproc;
(void) addnode (mtlist, p);
}
/* do tlist */
p = getnode ();
p->key = xstrdup (file);
p->type = UPDATE;
p->delproc = tag_delproc;
vers = Version_TS (repository, (char *) NULL, (char *) NULL,
(char *) NULL, file, 0, 0, entries, srcfiles);
p->data = RCS_getversion(vers->srcfile, numtag, date, force_tag_match, 0);
if (p->data != NULL)
{
int addit = 1;
char *oversion;
oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1, 0);
if (oversion == NULL)
{
if (delete)
{
addit = 0;
}
}
else if (strcmp(oversion, p->data) == 0)
{
addit = 0;
}
else if (!force_tag_move)
{
addit = 0;
}
if (oversion != NULL)
{
free(oversion);
}
if (!addit)
{
free(p->data);
p->data = NULL;
}
}
freevers_ts (&vers);
(void) addnode (tlist, p);
return (0);
}
static int
check_filesdoneproc(err, repos, update_dir)
int err;
char *repos;
char *update_dir;
{
int n;
Node *p;
p = findnode(mtlist, update_dir);
if (p != NULL)
{
tlist = ((struct master_lists *) p->data)->tlist;
}
else
{
tlist = (List *) NULL;
}
if ((tlist == NULL) || (tlist->list->next == tlist->list))
{
return (err);
}
if ((n = Parse_Info(CVSROOTADM_TAGINFO, repos, pretag_proc, 1)) > 0)
{
error (0, 0, "Pre-tag check failed");
err += n;
}
return (err);
}
static int
pretag_proc(repository, filter)
char *repository;
char *filter;
{
if (filter[0] == '/')
{
char *s, *cp;
s = xstrdup(filter);
for (cp=s; *cp; cp++)
{
if (isspace(*cp))
{
*cp = '\0';
break;
}
}
if (!isfile(s))
{
error (0, errno, "cannot find pre-tag filter '%s'", s);
free(s);
return (1);
}
free(s);
}
run_setup("%s %s %s %s",
filter,
symtag,
delete ? "del" : force_tag_move ? "mov" : "add",
repository);
walklist(tlist, pretag_list_proc, NULL);
return (run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY));
}
static void
masterlist_delproc(p)
Node *p;
{
struct master_lists *ml;
ml = (struct master_lists *)p->data;
dellist(&ml->tlist);
free(ml);
return;
}
static void
tag_delproc(p)
Node *p;
{
if (p->data != NULL)
{
free(p->data);
p->data = NULL;
}
return;
}
static int
pretag_list_proc(p, closure)
Node *p;
void *closure;
{
if (p->data != NULL)
{
run_arg(p->key);
run_arg(p->data);
}
return (0);
}
/*
* 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, 0);
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;
retcode = RCS_settag(rcsfile->path, 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.
*/
rev = branch_mode ? RCS_magicrev (rcsfile, version) : version;
oversion = RCS_getversion (rcsfile, symtag, (char *) NULL, 1, 0);
if (oversion != NULL)
{
int isbranch = RCS_isbranch (file, symtag, srcfiles);
/*
* if versions the same and neither old or new are branches don't
* have to do anything
*/
if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch)
{
free (oversion);
free (version);
return (0);
}
if (!force_tag_move) { /* we're NOT going to move the tag */
if (update_dir[0])
(void) printf ("W %s/%s", update_dir, file);
else
(void) printf ("W %s", file);
(void) printf (" : %s already exists on %s %s",
symtag, isbranch ? "branch" : "version", oversion);
(void) printf (" : NOT MOVING tag to %s %s\n",
branch_mode ? "branch" : "version", rev);
free (oversion);
free (version);
return (0);
}
free (oversion);
}
retcode = RCS_settag(rcsfile->path, symtag, rev);
}
if (retcode != 0)
{
error (1, 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 *) NULL, 1, 0);
if (version == NULL)
return (0);
free (version);
}
version = RCS_getversion (rcsfile, symtag, (char *) NULL, 1, 0);
if (version == NULL)
return (0);
free (version);
if ((retcode = RCS_deltag(rcsfile->path, symtag, 1)) != 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);
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,136 +0,0 @@
/* Interface between the server and the rest of CVS. */
/* Miscellaneous stuff which isn't actually particularly server-specific. */
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
#endif
#ifdef SERVER_SUPPORT
/*
* Nonzero if we are using the server. Used by various places to call
* server-specific functions.
*/
extern int server_active;
extern int server_expanding;
/* Server functions exported to the rest of CVS. */
/* Run the server. */
extern int server PROTO((int argc, char **argv));
/* We have a new Entries line for a file. TAG or DATE can be NULL. */
extern void server_register
PROTO((char *name, char *version, char *timestamp,
char *options, char *tag, char *date, char *conflict));
/*
* We want to nuke the Entries line for a file, and (unless
* server_scratch_entry_only is subsequently called) the file itself.
*/
extern void server_scratch PROTO((char *name));
/*
* The file which just had server_scratch called on it needs to have only
* the Entries line removed, not the file itself.
*/
extern void server_scratch_entry_only PROTO((void));
/*
* We just successfully checked in FILE (which is just the bare
* filename, with no directory). REPOSITORY is the directory for the
* repository.
*/
extern void server_checked_in
PROTO((char *file, char *update_dir, char *repository));
extern void server_copy_file
PROTO((char *file, char *update_dir, char *repository, char *newfile));
/*
* We just successfully updated FILE (bare filename, no directory).
* REPOSITORY is the directory for the repository. This is called
* after server_register or server_scratch, in the latter case the
* file is to be removed. UPDATED indicates whether the file is now
* up to date (SERVER_UPDATED, yes, SERVER_MERGED, no, SERVER_PATCHED,
* yes, but file is a diff from user version to repository version).
*/
enum server_updated_arg4 {SERVER_UPDATED, SERVER_MERGED, SERVER_PATCHED};
extern void server_updated
PROTO((char *file, char *update_dir, char *repository,
enum server_updated_arg4 updated, struct stat *,
unsigned char *checksum));
/* Set the Entries.Static flag. */
extern void server_set_entstat PROTO((char *update_dir, char *repository));
/* Clear it. */
extern void server_clear_entstat PROTO((char *update_dir, char *repository));
/* Set or clear a per-directory sticky tag or date. */
extern void server_set_sticky PROTO((char *update_dir, char *repository,
char *tag,
char *date));
extern void server_update_entries
PROTO((char *file, char *update_dir, char *repository,
enum server_updated_arg4 updated));
enum progs {PROG_CHECKIN, PROG_UPDATE};
extern void server_prog PROTO((char *, char *, enum progs));
extern void server_cleanup PROTO((int sig));
#ifdef SERVER_FLOWCONTROL
/* Pause if it's convenient to avoid memory blowout */
extern void server_check_pause PROTO((void));
#endif /* SERVER_FLOWCONTROL */
#endif /* SERVER_SUPPORT */
/* Stuff shared with the client. */
struct request
{
/* Name of the request. */
char *name;
#ifdef SERVER_SUPPORT
/*
* Function to carry out the request. ARGS is the text of the command
* after name and, if present, a single space, have been stripped off.
*/
void (*func) PROTO((char *args));
#endif
/* Stuff for use by the client. */
enum {
/*
* Failure to implement this request can imply a fatal
* error. This should be set only for commands which were in the
* original version of the protocol; it should not be set for new
* commands.
*/
rq_essential,
/* Some servers might lack this request. */
rq_optional,
/*
* Set by the client to one of the following based on what this
* server actually supports.
*/
rq_supported,
rq_not_supported,
/*
* If the server supports this request, and we do too, tell the
* server by making the request.
*/
rq_enableme
} status;
};
/* Table of requests ending with an entry with a NULL name. */
extern struct request requests[];
extern int use_unchanged;

View file

@ -1,282 +0,0 @@
/*
* 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.4 kit.
*
* Status Information
*/
#include "cvs.h"
#ifndef lint
static const char rcsid[] = "$CVSid: @(#)status.c 1.56 94/10/07 $";
USE(rcsid);
#endif
static Dtype status_dirproc PROTO((char *dir, char *repos, char *update_dir));
static int status_fileproc PROTO((char *file, char *update_dir,
char *repository, List * entries,
List * srcfiles));
static int tag_list_proc PROTO((Node * p, void *closure));
static int local = 0;
static int long_format = 0;
static char *xfile;
static List *xsrcfiles;
static const char *const 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 = 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;
wrap_setup ();
#ifdef CLIENT_SUPPORT
if (client_active) {
start_server ();
ign_setup ();
if (long_format)
send_arg("-v");
if (local)
send_arg("-l");
/* XXX This should only need to send file info; the file
contents themselves will not be examined. */
send_files (argc, argv, local, 0);
if (fprintf (to_server, "status\n") < 0)
error (1, errno, "writing to server");
err = get_responses_and_close ();
return err;
}
#endif
/* start the recursion processor */
err = start_recursion (status_fileproc, (FILESDONEPROC) NULL, status_dirproc,
(DIRLEAVEPROC) NULL, argc, argv, local,
W_LOCAL, 0, 1, (char *) NULL, 1, 0);
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,
update_dir, 0);
switch (status)
{
case T_UNKNOWN:
sstat = "Unknown";
break;
case T_CHECKOUT:
sstat = "Needs Checkout";
break;
#ifdef SERVER_SUPPORT
case T_PATCH:
sstat = "Needs Patch";
break;
#endif
case T_CONFLICT:
sstat = "Unresolved Conflict";
break;
case T_ADDED:
sstat = "Locally Added";
break;
case T_REMOVED:
sstat = "Locally Removed";
break;
case T_MODIFIED:
if (vers->ts_conflict)
sstat = "Unresolved Conflict";
else
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: %-17s\tStatus: %s\n\n", file, sstat);
if (vers->vn_user == NULL)
(void) printf (" Working revision:\tNo entry for %s\n", file);
else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
(void) printf (" Working revision:\tNew file!\n");
#ifdef SERVER_SUPPORT
else if (server_active)
(void) printf (" Working revision:\t%s\n", vers->vn_user);
#endif
else
(void) printf (" Working revision:\t%s\t%s\n", vers->vn_user,
vers->ts_rcs);
if (vers->vn_rcs == NULL)
(void) printf (" Repository revision:\tNo revision control file\n");
else
(void) printf (" Repository revision:\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
{
int isbranch = RCS_isbranch (file, edata->tag, srcfiles);
(void) printf (" Sticky Tag:\t\t%s (%s: %s)\n",
edata->tag,
isbranch ? "branch" : "revision",
isbranch ?
RCS_whatbranch(file, edata->tag, srcfiles) :
vers->vn_rcs);
}
}
}
else if (!really_quiet)
(void) printf (" Sticky Tag:\t\t(none)\n");
if (edata->date)
(void) printf (" Sticky Date:\t\t%s\n", edata->date);
else if (!really_quiet)
(void) printf (" Sticky Date:\t\t(none)\n");
if (edata->options && edata->options[0])
(void) printf (" Sticky Options:\t%s\n", edata->options);
else if (!really_quiet)
(void) printf (" Sticky Options:\t(none)\n");
if (long_format && vers->srcfile)
{
List *symbols = RCS_symbols(vers->srcfile);
(void) printf ("\n Existing Tags:\n");
if (symbols)
{
xfile = file;
xsrcfiles = srcfiles;
(void) walklist (symbols, tag_list_proc, NULL);
}
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, closure)
Node *p;
void *closure;
{
int isbranch = RCS_isbranch (xfile, p->key, xsrcfiles);
(void) printf ("\t%-25.25s\t(%s: %s)\n", p->key,
isbranch ? "branch" : "revision",
isbranch ? RCS_whatbranch(xfile, p->key, xsrcfiles) :
p->data);
return (0);
}

View file

@ -1,582 +0,0 @@
/*
* 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.4 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 const char rcsid[] = "$CVSid: @(#)tag.c 1.60 94/09/30 $";
USE(rcsid);
#endif
static int check_fileproc PROTO((char *file, char *update_dir,
char *repository, List * entries,
List * srcfiles));
static int check_filesdoneproc PROTO((int err, char *repos, char *update_dir));
static int pretag_proc PROTO((char *repository, char *filter));
static void masterlist_delproc PROTO((Node *p));
static void tag_delproc PROTO((Node *p));
static int pretag_list_proc PROTO((Node *p, void *closure));
static Dtype tag_dirproc PROTO((char *dir, char *repos, char *update_dir));
static int tag_fileproc PROTO((char *file, char *update_dir,
char *repository, List * entries,
List * srcfiles));
static char *numtag;
static char *date = NULL;
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 int force_tag_match = 1; /* force tag to match by default */
static int force_tag_move; /* don't force tag to move by default */
struct tag_info
{
Ctype status;
char *rev;
char *tag;
char *options;
};
struct master_lists
{
List *tlist;
};
static List *mtlist;
static List *tlist;
static const char *const tag_usage[] =
{
"Usage: %s %s [-lRF] [-b] [-d] tag [files...]\n",
"\t-l\tLocal directory only, not recursive.\n",
"\t-R\tProcess directories recursively.\n",
"\t-d\tDelete the given Tag.\n",
"\t-[rD]\tExisting tag or date.\n",
"\t-f\tForce a head revision if tag etc not found.\n",
"\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n",
"\t-F\tMove tag if it already exists\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 = getopt (argc, argv, "FQqlRdr:D:bf")) != -1)
{
switch (c)
{
case 'Q':
case 'q':
#ifdef SERVER_SUPPORT
/* The CVS 1.5 client sends these options (in addition to
Global_option requests), so we must ignore them. */
if (!server_active)
#endif
error (1, 0,
"-q or -Q must be specified before \"%s\"",
command_name);
break;
case 'l':
local = 1;
break;
case 'R':
local = 0;
break;
case 'd':
delete = 1;
break;
case 'r':
numtag = optarg;
break;
case 'D':
if (date)
free (date);
date = Make_Date (optarg);
break;
case 'f':
force_tag_match = 0;
break;
case 'b':
branch_mode = 1;
break;
case 'F':
force_tag_move = 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);
#ifdef CLIENT_SUPPORT
if (client_active)
{
/* We're the client side. Fire up the remote server. */
start_server ();
ign_setup ();
if (local)
send_arg("-l");
if (delete)
send_arg("-d");
if (branch_mode)
send_arg("-b");
if (force_tag_move)
send_arg("-F");
send_arg (symtag);
#if 0
/* FIXME: We shouldn't have to send current files, but I'm not sure
whether it works. So send the files --
it's slower but it works. */
send_file_names (argc, argv);
#else
send_files (argc, argv, local, 0);
#endif
if (fprintf (to_server, "tag\n") < 0)
error (1, errno, "writing to server");
return get_responses_and_close ();
}
#endif
/* check to make sure they are authorized to tag all the
specified files in the repository */
mtlist = getlist();
err = start_recursion (check_fileproc, check_filesdoneproc,
(DIRENTPROC) NULL, (DIRLEAVEPROC) NULL,
argc, argv, local, W_LOCAL, 0, 1,
(char *) NULL, 1, 0);
if (err)
{
error (1, 0, "correct the above errors first!");
}
/* start the recursion processor */
err = start_recursion (tag_fileproc, (FILESDONEPROC) NULL, tag_dirproc,
(DIRLEAVEPROC) NULL, argc, argv, local,
W_LOCAL, 0, 1, (char *) NULL, 1, 0);
dellist(&mtlist);
return (err);
}
/* check file that is to be tagged */
/* All we do here is add it to our list */
static int
check_fileproc(file, update_dir, repository, entries, srcfiles)
char *file;
char *update_dir;
char *repository;
List * entries;
List * srcfiles;
{
char *xdir;
Node *p;
Vers_TS *vers;
if (update_dir[0] == '\0')
xdir = ".";
else
xdir = update_dir;
if ((p = findnode (mtlist, xdir)) != NULL)
{
tlist = ((struct master_lists *) p->data)->tlist;
}
else
{
struct master_lists *ml;
tlist = getlist ();
p = getnode ();
p->key = xstrdup (xdir);
p->type = UPDATE;
ml = (struct master_lists *)
xmalloc (sizeof (struct master_lists));
ml->tlist = tlist;
p->data = (char *) ml;
p->delproc = masterlist_delproc;
(void) addnode (mtlist, p);
}
/* do tlist */
p = getnode ();
p->key = xstrdup (file);
p->type = UPDATE;
p->delproc = tag_delproc;
vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL,
file, 0, 0, entries, srcfiles);
p->data = RCS_getversion(vers->srcfile, numtag, date, force_tag_match, 0);
if (p->data != NULL)
{
int addit = 1;
char *oversion;
oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1, 0);
if (oversion == NULL)
{
if (delete)
{
addit = 0;
}
}
else if (strcmp(oversion, p->data) == 0)
{
addit = 0;
}
else if (!force_tag_move)
{
addit = 0;
}
if (oversion != NULL)
{
free(oversion);
}
if (!addit)
{
free(p->data);
p->data = NULL;
}
}
freevers_ts(&vers);
(void) addnode (tlist, p);
return (0);
}
static int
check_filesdoneproc(err, repos, update_dir)
int err;
char *repos;
char *update_dir;
{
int n;
Node *p;
p = findnode(mtlist, update_dir);
if (p != NULL)
{
tlist = ((struct master_lists *) p->data)->tlist;
}
else
{
tlist = (List *) NULL;
}
if ((tlist == NULL) || (tlist->list->next == tlist->list))
{
return (err);
}
if ((n = Parse_Info(CVSROOTADM_TAGINFO, repos, pretag_proc, 1)) > 0)
{
error (0, 0, "Pre-tag check failed");
err += n;
}
return (err);
}
static int
pretag_proc(repository, filter)
char *repository;
char *filter;
{
if (filter[0] == '/')
{
char *s, *cp;
s = xstrdup(filter);
for (cp=s; *cp; cp++)
{
if (isspace(*cp))
{
*cp = '\0';
break;
}
}
if (!isfile(s))
{
error (0, errno, "cannot find pre-tag filter '%s'", s);
free(s);
return (1);
}
free(s);
}
run_setup("%s %s %s %s",
filter,
symtag,
delete ? "del" : force_tag_move ? "mov" : "add",
repository);
walklist(tlist, pretag_list_proc, NULL);
return (run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY));
}
static void
masterlist_delproc(p)
Node *p;
{
struct master_lists *ml;
ml = (struct master_lists *)p->data;
dellist(&ml->tlist);
free(ml);
return;
}
static void
tag_delproc(p)
Node *p;
{
if (p->data != NULL)
{
free(p->data);
p->data = NULL;
}
return;
}
static int
pretag_list_proc(p, closure)
Node *p;
void *closure;
{
if (p->data != NULL)
{
run_arg(p->key);
run_arg(p->data);
}
return (0);
}
/*
* 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 *nversion = NULL;
char *rev;
Vers_TS *vers;
int retcode = 0;
vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL,
file, 0, 0, entries, srcfiles);
if ((numtag != NULL) || (date != NULL))
{
nversion = RCS_getversion(vers->srcfile,
numtag,
date,
force_tag_match, 0);
if (nversion == NULL)
{
freevers_ts (&vers);
return (0);
}
}
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, 0);
if (version == NULL || vers->srcfile == NULL)
{
freevers_ts (&vers);
return (0);
}
free (version);
if ((retcode = RCS_deltag(vers->srcfile->path, symtag, 1)) != 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.
*/
if (nversion == NULL)
{
version = vers->vn_user;
}
else
{
version = nversion;
}
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.
*/
rev = branch_mode ? RCS_magicrev (vers->srcfile, version) : version;
oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1, 0);
if (oversion != NULL)
{
int isbranch = RCS_isbranch (file, symtag, srcfiles);
/*
* if versions the same and neither old or new are branches don't have
* to do anything
*/
if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch)
{
free (oversion);
freevers_ts (&vers);
return (0);
}
if (!force_tag_move) { /* we're NOT going to move the tag */
if (update_dir[0])
(void) printf ("W %s/%s", update_dir, file);
else
(void) printf ("W %s", file);
(void) printf (" : %s already exists on %s %s",
symtag, isbranch ? "branch" : "version", oversion);
(void) printf (" : NOT MOVING tag to %s %s\n",
branch_mode ? "branch" : "version", rev);
free (oversion);
freevers_ts (&vers);
return (0);
}
free (oversion);
}
if ((retcode = RCS_settag(vers->srcfile->path, symtag, rev)) != 0)
{
error (1, 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);
if (nversion != NULL)
{
free(nversion);
}
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);
}

File diff suppressed because it is too large Load diff

View file

@ -1,9 +0,0 @@
/* Definitions of routines shared between local and client/server
"update" code. */
/* List of files that we have either processed or are willing to
ignore. Any file not on this list gets a question mark printed. */
extern List *ignlist;
extern int
update_filesdone_proc PROTO((int err, char *repository, char *update_dir));

View file

@ -1,326 +0,0 @@
/*
* 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.4 kit.
*/
#include "cvs.h"
#ifndef lint
static const char rcsid[] = "$CVSid: @(#)vers_ts.c 1.45 94/10/07 $";
USE(rcsid);
#endif
#ifdef SERVER_SUPPORT
static void time_stamp_server PROTO((char *, Vers_TS *));
#endif
/*
* 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));
memset ((char *) vers_ts, 0, 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);
vers_ts->ts_conflict = xstrdup (entdata->conflict);
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 if (repository != NULL)
rcsdata = RCS_parse (user, repository);
else
rcsdata = NULL;
if (rcsdata != NULL)
{
/* squirrel away the rcsdata pointer for others */
vers_ts->srcfile = rcsdata;
#ifndef DEATH_SUPPORT
/* (is this indeed death support? I haven't looked carefully). */
/* 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))
{
#endif
if (vers_ts->tag && strcmp (vers_ts->tag, TAG_BASE) == 0)
{
vers_ts->vn_rcs = xstrdup (vers_ts->vn_user);
vers_ts->vn_tag = xstrdup (vers_ts->vn_user);
}
else
{
vers_ts->vn_rcs = RCS_getversion (rcsdata, vers_ts->tag,
vers_ts->date, force_tag_match, 1);
if (vers_ts->vn_rcs == NULL)
vers_ts->vn_tag = NULL;
else
{
char *colon = strchr (vers_ts->vn_rcs, ':');
if (colon)
{
vers_ts->vn_tag = xstrdup (colon+1);
*colon = '\0';
}
else
vers_ts->vn_tag = xstrdup (vers_ts->vn_rcs);
}
}
#ifndef DEATH_SUPPORT
}
#endif
/*
* 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;
memset ((char *) &t, 0, sizeof (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)
{
#ifdef SERVER_SUPPORT
if (server_active)
time_stamp_server (user, vers_ts);
else
#endif
vers_ts->ts_user = time_stamp (user);
}
return (vers_ts);
}
#ifdef SERVER_SUPPORT
/* Set VERS_TS->TS_USER to time stamp for FILE. */
/* Separate these out to keep the logic below clearer. */
#define mark_lost(V) ((V)->ts_user = 0)
#define mark_unchanged(V) ((V)->ts_user = xstrdup ((V)->ts_rcs))
static void
time_stamp_server (file, vers_ts)
char *file;
Vers_TS *vers_ts;
{
struct stat sb;
char *cp;
if (stat (file, &sb) < 0)
{
if (! existence_error (errno))
error (1, errno, "cannot stat temp file");
if (use_unchanged)
{
/* Missing file means lost or unmodified; check entries
file to see which.
XXX FIXME - If there's no entries file line, we
wouldn't be getting the file at all, so consider it
lost. I don't know that that's right, but it's not
clear to me that either choice is. Besides, would we
have an RCS string in that case anyways? */
if (vers_ts->entdata == NULL)
mark_lost (vers_ts);
else if (vers_ts->entdata->timestamp
&& vers_ts->entdata->timestamp[0] == '=')
mark_unchanged (vers_ts);
else
mark_lost (vers_ts);
}
else
{
/* Missing file in the temp directory means that the file
was not modified. */
mark_unchanged (vers_ts);
}
}
else if (sb.st_mtime == 0)
{
if (use_unchanged)
/* We shouldn't reach this case any more! */
abort ();
/* Special code used by server.c to indicate the file was lost. */
mark_lost (vers_ts);
}
else
{
vers_ts->ts_user = xmalloc (25);
cp = asctime (gmtime (&sb.st_mtime)); /* copy in the modify time */
cp[24] = 0;
(void) strcpy (vers_ts->ts_user, cp);
}
}
#endif /* SERVER_SUPPORT */
/*
* 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 (25);
cp = asctime (gmtime (&sb.st_mtime)); /* copy in the modify time */
cp[24] = 0;
(void) strcpy (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)->vn_tag)
free ((*versp)->vn_tag);
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);
if ((*versp)->ts_conflict)
free ((*versp)->ts_conflict);
free ((char *) *versp);
*versp = (Vers_TS *) NULL;
}

View file

@ -1,371 +0,0 @@
#include "cvs.h"
/*
Original Author: athan@morgan.com <Andrew C. Athan> 2/1/94
Modified By: vdemarco@bou.shl.com
This package was written to support the NEXTSTEP concept of
"wrappers." These are essentially directories that are to be
treated as "files." This package allows such wrappers to be
"processed" on the way in and out of CVS. The intended use is to
wrap up a wrapper into a single tar, such that that tar can be
treated as a single binary file in CVS. To solve the problem
effectively, it was also necessary to be able to prevent rcsmerge
application at appropriate times.
------------------
Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)
wildcard [option value][option value]...
where option is one of
-f from cvs filter value: path to filter
-t to cvs filter value: path to filter
-m update methodology value: MERGE or COPY
and value is a single-quote delimited value.
E.g:
*.nib -f 'gunzipuntar' -t 'targzip' -m 'COPY'
*/
typedef struct {
char *wildCard;
char *tocvsFilter;
char *fromcvsFilter;
char *conflictHook;
WrapMergeMethod mergeMethod;
} WrapperEntry;
static WrapperEntry **wrap_list=NULL;
static WrapperEntry **wrap_saved_list=NULL;
static int wrap_size=0;
static int wrap_count=0;
static int wrap_tempcount=0;
static int wrap_saved_count=0;
static int wrap_saved_tempcount=0;
#define WRAPPER_GROW 8
void wrap_add_entry PROTO((WrapperEntry *e,int temp));
void wrap_kill PROTO((void));
void wrap_kill_temp PROTO((void));
void wrap_free_entry PROTO((WrapperEntry *e));
void wrap_free_entry_internal PROTO((WrapperEntry *e));
void wrap_restore_saved PROTO((void));
void wrap_setup()
{
char file[PATH_MAX];
struct passwd *pw;
/* Then add entries found in repository, if it exists */
(void) sprintf (file, "%s/%s/%s", CVSroot, CVSROOTADM, CVSROOTADM_WRAPPER);
if (isfile (file)){
wrap_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, CVSDOTWRAPPER);
if (isfile (file)){
wrap_add_file (file, 0);
}
}
/* Then add entries found in CVSWRAPPERS environment variable. */
wrap_add (getenv (WRAPPER_ENV), 0);
}
/*
* Open a file and read lines, feeding each line to a line parser. Arrange
* for keeping a temporary list of wrappers at the end, if the "temp"
* argument is set.
*/
void
wrap_add_file (file, temp)
const char *file;
int temp;
{
FILE *fp;
char line[1024];
wrap_restore_saved();
wrap_kill_temp();
/* load the file */
if (!(fp = fopen (file, "r")))
return;
while (fgets (line, sizeof (line), fp))
wrap_add (line, temp);
(void) fclose (fp);
}
void
wrap_kill()
{
wrap_kill_temp();
while(wrap_count)
wrap_free_entry(wrap_list[--wrap_count]);
}
void
wrap_kill_temp()
{
WrapperEntry **temps=wrap_list+wrap_count;
while(wrap_tempcount)
wrap_free_entry(temps[--wrap_tempcount]);
}
void
wrap_free_entry(e)
WrapperEntry *e;
{
wrap_free_entry_internal(e);
free(e);
}
void
wrap_free_entry_internal(e)
WrapperEntry *e;
{
free(e->wildCard);
if(e->tocvsFilter)
free(e->tocvsFilter);
if(e->fromcvsFilter)
free(e->fromcvsFilter);
if(e->conflictHook)
free(e->conflictHook);
}
void
wrap_restore_saved()
{
if(!wrap_saved_list)
return;
wrap_kill();
free(wrap_list);
wrap_list=wrap_saved_list;
wrap_count=wrap_saved_count;
wrap_tempcount=wrap_saved_tempcount;
wrap_saved_list=NULL;
wrap_saved_count=0;
wrap_saved_tempcount=0;
}
void
wrap_add (line, isTemp)
char *line;
int isTemp;
{
char *temp;
char ctemp;
WrapperEntry e;
char opt;
if (!line || line[0] == '#')
return;
memset (&e, 0, sizeof(e));
/* Search for the wild card */
while(*line && isspace(*line))
++line;
for(temp=line;*line && !isspace(*line);++line)
;
if(temp==line)
return;
ctemp=*line;
*line='\0';
e.wildCard=xstrdup(temp);
*line=ctemp;
while(*line){
/* Search for the option */
while(*line && *line!='-')
++line;
if(!*line)
break;
++line;
if(!*line)
break;
opt=*line;
/* Search for the filter commandline */
for(++line;*line && *line!='\'';++line);
if(!*line)
break;
for(temp=++line;*line && (*line!='\'' || line[-1]=='\\');++line)
;
if(line==temp+1)
break;
ctemp=*line;
*line='\0';
switch(opt){
case 'f':
if(e.fromcvsFilter)
free(e.fromcvsFilter);
e.fromcvsFilter=expand_path (temp);
if (!e.fromcvsFilter)
error (1, 0,
"Invalid environmental variable string '%s'",temp);
break;
case 't':
if(e.tocvsFilter)
free(e.tocvsFilter);
e.tocvsFilter=expand_path (temp);
if (!e.tocvsFilter)
error (1, 0,
"Invalid environmental variable string '%s'",temp);
break;
case 'c':
if(e.conflictHook)
free(e.conflictHook);
e.conflictHook=expand_path (temp);
if (!e.conflictHook)
error (1, 0,
"Invalid environmental variable string '%s'",temp);
break;
case 'm':
if(*temp=='C' || *temp=='c')
e.mergeMethod=WRAP_COPY;
else
e.mergeMethod=WRAP_MERGE;
break;
default:
break;
}
*line=ctemp;
if(!*line)break;
++line;
}
wrap_add_entry(&e, isTemp);
}
void
wrap_add_entry(e, temp)
WrapperEntry *e;
int temp;
{
int x;
if(wrap_count+wrap_tempcount>=wrap_size){
wrap_size += WRAPPER_GROW;
wrap_list = (WrapperEntry **) xrealloc ((char *) wrap_list,
wrap_size *
sizeof (WrapperEntry *));
}
if(!temp && wrap_tempcount){
for(x=wrap_count+wrap_tempcount-1;x>=wrap_count;--x)
wrap_list[x+1]=wrap_list[x];
}
x=(temp ? wrap_count+(wrap_tempcount++):(wrap_count++));
wrap_list[x]=(WrapperEntry *)xmalloc(sizeof(WrapperEntry));
wrap_list[x]->wildCard=e->wildCard;
wrap_list[x]->fromcvsFilter=e->fromcvsFilter;
wrap_list[x]->tocvsFilter=e->tocvsFilter;
wrap_list[x]->conflictHook=e->conflictHook;
wrap_list[x]->mergeMethod=e->mergeMethod;
}
/* Return 1 if the given filename is a wrapper filename */
int
wrap_name_has (name,has)
const char *name;
WrapMergeHas has;
{
int x,count=wrap_count+wrap_saved_count;
char *temp;
for(x=0;x<count;++x)
if (fnmatch (wrap_list[x]->wildCard, name, 0) == 0){
switch(has){
case WRAP_TOCVS:
temp=wrap_list[x]->tocvsFilter;
break;
case WRAP_FROMCVS:
temp=wrap_list[x]->fromcvsFilter;
break;
case WRAP_CONFLICT:
temp=wrap_list[x]->conflictHook;
break;
default:
abort ();
}
if(temp==NULL)
return (0);
else
return (1);
}
return (0);
}
WrapperEntry *
wrap_matching_entry (name)
const char *name;
{
int x,count=wrap_count+wrap_saved_count;
for(x=0;x<count;++x)
if (fnmatch (wrap_list[x]->wildCard, name, 0) == 0)
return wrap_list[x];
return (WrapperEntry *)NULL;
}
char *
wrap_tocvs_process_file(fileName)
const char *fileName;
{
WrapperEntry *e=wrap_matching_entry(fileName);
static char buf[L_tmpnam+1];
if(e==NULL || e->tocvsFilter==NULL)
return NULL;
tmpnam(buf);
run_setup(e->tocvsFilter,fileName,buf);
run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY );
return buf;
}
int
wrap_merge_is_copy (fileName)
const char *fileName;
{
WrapperEntry *e=wrap_matching_entry(fileName);
if(e==NULL || e->mergeMethod==WRAP_MERGE)
return 0;
return 1;
}
char *
wrap_fromcvs_process_file(fileName)
const char *fileName;
{
WrapperEntry *e=wrap_matching_entry(fileName);
static char buf[PATH_MAX];
if(e==NULL || e->fromcvsFilter==NULL)
return NULL;
run_setup(e->fromcvsFilter,fileName);
run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL );
return buf;
}

View file

@ -1,4 +1,9 @@
# $Id: Makefile,v 1.2 1995/12/11 01:58:51 peter Exp $
# $Id: Makefile,v 1.3 1995/12/11 04:24:06 peter Exp $
.include "${.CURDIR}/../Makefile.inc"
.PATH: ${CVSDIR}/src
.PATH: ${CVSDIR}/man
MAN8= cvsbug.8
@ -9,17 +14,15 @@ CLEANFILES+= cvsbug ver
all: cvsbug
.sh:
echo > ver cvs-`sed < ${.CURDIR}/../lib/version.c \
echo > ver cvs-`sed < ${CVSDIR}/src/version.c \
-e '/version_string/!d' \
-e 's/[^0-9.]*\([0-9.]*\).*/\1/' \
-e q`
sed -e "s,xVERSIONx,`cat ver`,g" ${.CURDIR}/$@.sh > $@
sed -e "s,xVERSIONx,`cat ver`,g" $> > $@
beforeinstall:
${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
cvsbug ${DESTDIR}${BINDIR}/cvsbug
.include "../../Makefile.inc"
.include <bsd.prog.mk>

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