mirror of
https://github.com/opnsense/src.git
synced 2026-04-22 23:02:02 -04:00
Update to use the cvs-1.8.1 sources from src/contrib/cvs
This commit is contained in:
parent
7e0b7d4a87
commit
8787dbbafe
154 changed files with 125 additions and 76724 deletions
|
|
@ -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.
|
||||
10006
gnu/usr.bin/cvs/FAQ
10006
gnu/usr.bin/cvs/FAQ
File diff suppressed because it is too large
Load diff
|
|
@ -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.
|
||||
-------------------------------------------------------------------------------
|
||||
|
|
@ -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?
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 $
|
||||
|
|
@ -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.
|
||||
|
|
@ -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>
|
||||
|
|
@ -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.
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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.
|
||||
|
||||
|
|
@ -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.
|
||||
|
||||
|
|
@ -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>
|
||||
|
|
@ -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---
|
||||
|
|
@ -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)
|
||||
|
|
@ -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)))
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
#! /bin/sh
|
||||
emacs -batch -l compile-all.el -f compile-pcl-cvs
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
@ -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.
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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.
|
||||
|
|
@ -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));
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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.
|
||||
*/
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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. */
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
#define PATCHLEVEL 2
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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));
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
Loading…
Reference in a new issue